--- channels/chan_sip.c.orig	2010-10-16 02:12:04.000000000 +0600
+++ channels/chan_sip.c	2010-12-08 03:00:54.000000000 +0500
@@ -700,6 +700,7 @@
 
 static unsigned int chan_idx;       /*!< used in naming sip channel */
 static int global_match_auth_username;    /*!< Match auth username if available instead of From: Default off. */
+static int global_match_callbackexten;    /*!< Match peer callback extension: Default off. */
 
 static int global_relaxdtmf;        /*!< Relax DTMF */
 static int global_prematuremediafilter;   /*!< Enable/disable premature frames in a call (causing 183 early media) */
@@ -14842,6 +14843,23 @@
 	}
 }
 
+
+static int peer_match_callbackextension_cb(void *obj, void *arg, void *data, int flags)
+{
+	struct sip_peer *peer = arg;
+	struct sip_peer *peer2 = obj;
+	char *callback = data;
+
+	if (!ast_sockaddr_cmp_addr(&peer->addr, &peer2->addr) &&
+		(ast_sockaddr_port(&peer->addr) == ast_sockaddr_port(&peer2->addr)) &&
+		(!strcasecmp(callback, peer2->callback))) {
+		return CMP_MATCH | CMP_STOP;
+	}
+
+	return 0;
+}
+
+
 /*! \brief Validate device authentication */
 static enum check_auth_result check_peer_ok(struct sip_pvt *p, char *of,
 	struct sip_request *req, int sipmethod, struct ast_sockaddr *addr,
@@ -14864,6 +14882,20 @@
 		/* Then find devices based on IP */
 		if (!peer) {
 			peer = find_peer(NULL, &p->recv, TRUE, FINDPEERS, FALSE, p->socket.type);
+			/* if peer is found by ip, and match_callbackextension is enabled, check
+			 * to see if there is a tighter peer match by comparing the peer's callback*/
+			if (peer && global_match_callbackexten) {
+				char *uri_tmp, *callback = NULL, *dummy, *domain;
+				uri_tmp = ast_strdupa(uri2);
+				parse_uri(uri_tmp, "sip:,sips:", &callback, &dummy, &domain, &dummy);
+				if (!ast_strlen_zero(callback) && strcasecmp(callback, peer->callback)) {
+					struct sip_peer *peer2;
+					if ((peer2 = ao2_t_callback_data(peers_by_ip, OBJ_POINTER, peer_match_callbackextension_cb, peer, callback, "ao2_find in peers_by_ip table, matching callback"))) {
+						unref_peer(peer, "check_peer_ok: unref_peer: new peer with better matching callback extension found, tossing this one");
+						peer = peer2;
+					}
+				}
+			}
 		}
 	}
 
@@ -25543,6 +25575,7 @@
 	ast_string_field_set(peer, fromdomain, "");
 	ast_string_field_set(peer, fromuser, "");
 	ast_string_field_set(peer, regexten, "");
+	ast_string_field_set(peer, callback, "");
 	peer->callgroup = 0;
 	peer->pickupgroup = 0;
 	peer->maxms = default_qualify;
@@ -25642,7 +25675,6 @@
 	time_t regseconds = 0;
 	struct ast_flags peerflags[3] = {{(0)}};
 	struct ast_flags mask[3] = {{(0)}};
-	char callback[256] = "";
 	struct sip_peer tmp_peer;
 	const char *srvlookup = NULL;
 	static int deprecation_warning = 1;
@@ -25916,7 +25948,7 @@
 			} else if (!strcasecmp(v->name, "regexten")) {
 				ast_string_field_set(peer, regexten, v->value);
 			} else if (!strcasecmp(v->name, "callbackextension")) {
-				ast_copy_string(callback, v->value, sizeof(callback));
+				ast_string_field_set(peer, callback, v->value);
 			} else if (!strcasecmp(v->name, "amaflags")) {
 				format = ast_cdr_amaflags2int(v->value);
 				if (format < 0) {
@@ -26280,9 +26312,9 @@
 
 	ast_free_ha(oldha);
 	ast_free_ha(olddirectmediaha);
-	if (!ast_strlen_zero(callback)) { /* build string from peer info */
+	if (!ast_strlen_zero(peer->callback)) { /* build string from peer info */
 		char *reg_string;
-		if (asprintf(&reg_string, "%s?%s:%s@%s/%s", peer->name, peer->username, !ast_strlen_zero(peer->remotesecret) ? peer->remotesecret : peer->secret, peer->tohost, callback) < 0) {
+		if (asprintf(&reg_string, "%s?%s:%s@%s/%s", peer->name, peer->username, !ast_strlen_zero(peer->remotesecret) ? peer->remotesecret : peer->secret, peer->tohost, peer->callback) < 0) {
 			ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno));
 		} else if (reg_string) {
 			sip_register(reg_string, 0); /* XXX TODO: count in registry_count */
@@ -26483,6 +26515,7 @@
 	sip_cfg.allowguest = DEFAULT_ALLOWGUEST;
 	global_callcounter = DEFAULT_CALLCOUNTER;
 	global_match_auth_username = FALSE;		/*!< Match auth username if available instead of From: Default off. */
+	global_match_callbackexten = FALSE;
 	global_rtptimeout = 0;
 	global_rtpholdtimeout = 0;
 	global_rtpkeepalive = DEFAULT_RTPKEEPALIVE;
@@ -26774,6 +26807,8 @@
 			sip_cfg.autocreatepeer = ast_true(v->value);
 		} else if (!strcasecmp(v->name, "match_auth_username")) {
 			global_match_auth_username = ast_true(v->value);
+		} else if (!strcasecmp(v->name, "match_callbackextension")) {
+			global_match_callbackexten = ast_true(v->value);
 		} else if (!strcasecmp(v->name, "srvlookup")) {
 			sip_cfg.srvlookup = ast_true(v->value);
 		} else if (!strcasecmp(v->name, "pedantic")) {
--- configs/sip.conf.sample.orig	2010-09-04 04:21:50.000000000 +0600
+++ configs/sip.conf.sample	2010-12-07 23:23:40.000000000 +0500
@@ -121,6 +121,9 @@
 ;match_auth_username=yes        ; if available, match user entry using the
                                 ; 'username' field from the authentication line
                                 ; instead of the From: field.
+;match_callbackextension=yes    ; Attempt to match peers by callbackextension when possible.
+                                ; This may be used to differentiate peers with the same address
+                                ; containing separate callbackextensions. Off by default.
 allowoverlap=no                 ; Disable overlap dialing support. (Default is yes)
 ;allowtransfer=no               ; Disable all transfers (unless enabled in peers or users)
                                 ; Default is enabled. The Dial() options 't' and 'T' are not
--- channels/sip/include/sip.h.orig	2010-12-07 23:29:43.000000000 +0500
+++ channels/sip/include/sip.h	2010-12-07 23:28:57.000000000 +0500
@@ -1169,6 +1169,7 @@
 		AST_STRING_FIELD(mwi_from);     /*!< Name to place in From header for outgoing NOTIFY requests */
 		AST_STRING_FIELD(engine);       /*!<  RTP Engine to use */
 		AST_STRING_FIELD(unsolicited_mailbox);  /*!< Mailbox to store received unsolicited MWI NOTIFY messages information in */
+		AST_STRING_FIELD(callback);     /*!< Holds callbackextension if specified */
 		);
 	struct sip_socket socket;       /*!< Socket used for this peer */
 	enum sip_transport default_outbound_transport;   /*!< Peer Registration may change the default outbound transport.
