Index: chan_sip.c
===================================================================
--- chan_sip.c	(revision 42085)
+++ chan_sip.c	(working copy)
@@ -4158,7 +4158,6 @@
 static struct sip_pvt *find_call(struct sip_request *req, struct sockaddr_in *sin, const int intended_method)
 {
 	struct sip_pvt *p;
-	char *tag = "";	/* note, tag is never NULL */
 	char totag[128];
 	char fromtag[128];
 	const char *callid = get_header(req, "Call-ID");
@@ -4180,40 +4179,70 @@
 			ast_set_flag(req, SIP_PKT_WITH_TOTAG);	/* Used in handle_request/response */
 		gettag(req, "From", fromtag, sizeof(fromtag));
 
-		tag = (req->method == SIP_RESPONSE) ? totag : fromtag;
-
 		if (option_debug > 4 )
-			ast_log(LOG_DEBUG, "= Looking for  Call ID: %s (Checking %s) --From tag %s --To-tag %s  \n", callid, req->method==SIP_RESPONSE ? "To" : "From", fromtag, totag);
+			ast_log(LOG_DEBUG, "= Looking for  Call ID: %s --From tag %s --To-tag %s (request) \n", callid, fromtag, totag);
 	}
 
 	ast_mutex_lock(&iflock);
 	for (p = iflist; p; p = p->next) {
-		/* In pedantic, we do not want packets with bad syntax to be connected to a PVT */
-		int found = FALSE;
-		if (req->method == SIP_REGISTER)
-			found = (!strcmp(p->callid, callid));
-		else 
-			found = (!strcmp(p->callid, callid) && 
-			(!pedanticsipchecking || !tag || ast_strlen_zero(p->theirtag) || !strcmp(p->theirtag, tag))) ;
-
-		if (option_debug > 4)
-			ast_log(LOG_DEBUG, "= %s Their Call ID: %s Their Tag %s Our tag: %s\n", found ? "Found" : "No match", p->callid, p->theirtag, p->tag);
+		const char *their_local_tag;
+		const char *their_remote_tag;
+		const char *mandatory_chan_tag;
+		const char *mandatory_req_tag;
+		int chan_is_outgoing = ast_test_flag(&p->flags[0], SIP_OUTGOING);
+		int found = !strcmp(p->callid, callid);
 
-		/* If we get a new request within an existing to-tag - check the to tag as well */
-		if (pedanticsipchecking && found  && req->method != SIP_RESPONSE) {	/* SIP Request */
-			if (p->tag[0] == '\0' && totag[0]) {
-				/* We have no to tag, but they have. Wrong dialog */
+		/* In pedantic, we do not want packets with bad syntax to be connected to a PVT */
+		if (req->method != SIP_REGISTER && found && pedanticsipchecking) { 
+			if (req->method == SIP_RESPONSE) {
+				their_local_tag = totag;
+				their_remote_tag = fromtag;
+			}
+			else {
+				their_local_tag = fromtag;
+				their_remote_tag = totag;
+			}
+			if (chan_is_outgoing) {
+				/* Channel is UAC. Local tag of the channel must exist at the both sides. */
+				mandatory_chan_tag = p->tag;
+				mandatory_req_tag = their_remote_tag;
+			}
+			else {
+				/* Channel is UAS. Local tag of the peer must exist at the both sides. */
+				mandatory_chan_tag = p->theirtag;
+				mandatory_req_tag = their_local_tag;
+			}
+			/* Check mandatory tag first */
+			if (mandatory_chan_tag[0] == '\0' || mandatory_req_tag[0] == '\0')
+				/* Either side doesn't have mandatory tag. Wrong dialog. */
 				found = FALSE;
-			} else if (totag[0]) {			/* Both have tags, compare them */
-				if (strcmp(totag, p->tag)) {
-					found = FALSE;		/* This is not our packet */
+			else
+			       	/* Both have tags, compare them */
+				found = !strcmp(mandatory_chan_tag, mandatory_req_tag);
+			if (found) {
+				const char *optional_tag_origin;
+				const char *optional_tag_peer;
+				if (chan_is_outgoing) {
+					/* Channel is UAC. Remote tag of the channel may be still unset */
+					optional_tag_origin = their_local_tag;
+					optional_tag_peer = p->theirtag;
+				}
+				else {
+					/* Channel is UAS. Remote tag of the peer may be still unset */
+					optional_tag_origin = p->tag;
+					optional_tag_peer = their_remote_tag;
 				}
+				if (optional_tag_origin[0] == '\0' && optional_tag_peer[0] != '\0')
+					/* Originator has no tag, but peer has. Wrong dialog. */
+					found = FALSE;
+				else if (optional_tag_peer[0] != '\0')
+					/* Both have tags, compare them */
+					found = !strcmp(optional_tag_origin, optional_tag_peer);
 			}
-			if (!found && option_debug > 4)
-				ast_log(LOG_DEBUG, "= Being pedantic: This is not our match on request: Call ID: %s Ourtag <null> Totag %s Method %s\n", p->callid, totag, sip_methods[req->method].text);
 		}
 
-
+		if (option_debug > 4)
+			ast_log(LOG_DEBUG, "= %s Their Call ID: %s Their Tag %s Our tag: %s Initial chan role: %s\n", found ? "Found" : "No match", p->callid, p->theirtag, p->tag, (chan_is_outgoing ? "UAC" : "UAS"));
 		if (found) {
 			/* Found the call */
 			ast_mutex_lock(&p->lock);
@@ -4221,9 +4250,16 @@
 			return p;
 		}
 	}
+	/* Call not found. */
 	ast_mutex_unlock(&iflock);
+        /* Drop requests that cannot exist outside SIP dialog and cannot create new dialog. */
+	if (req->method == SIP_RESPONSE || req->method == SIP_ACK ||
+	    req->method == SIP_BYE || req->method == SIP_CANCEL)
+	{
+		p = NULL;
+	}
 	/* Allocate new call */
-	if ((p = sip_alloc(callid, sin, 1, intended_method)))
+	else if ((p = sip_alloc(callid, sin, 1, intended_method)))
 		ast_mutex_lock(&p->lock);
 	return p;
 }
