+@@ -6456,7 +6494,13 @@
+ char *name, *c;
+ char *t;
+ char *domain;
+-
++ char *callid;
++ struct sip_peer *clone;
++ char clone_name[256];
++ int found = 0;
++ struct sip_peer *recycle_peer = NULL;
++ char peer_name[256];
++
+ /* Terminate URI */
+ t = uri;
+ while(*t && (*t > 32) && (*t != ';'))
+@@ -6505,9 +6549,68 @@
+ if (!ast_test_flag(&peer->flags_page2, SIP_PAGE2_DYNAMIC)) {
+ ast_log(LOG_ERROR, "Peer '%s' is trying to register, but not configured as host=dynamic\n", peer->name);
+ } else {
++ callid = get_header(req, "Call-ID");
++ ast_copy_string(peer_name, peer->name, sizeof(peer_name));
++ if (peer->max_regs > 1) {
++ int i = 0;
++ /* check if peer matches callid */
++ if ((peer->expire > -1) && (!strncmp(peer->reg_callid, callid, strlen(callid)))) {
++ // ast_log(LOG_NOTICE, "peer->reg_callid %s, req->callid %s found in peer\n", peer->reg_callid, callid);
++ found++;
++ } else {
++ /* otherwise check subpeers for callid */
++ for (i=0; i<peer->max_regs - 1; i++) {
++ snprintf(clone_name, sizeof(clone_name), "%s@%d", peer->name, i);
++ // ast_log(LOG_NOTICE, "checking subpeer %s\n", clone_name);
++ clone = find_peer(clone_name, NULL, 1);
++ if (clone && (clone->expire > -1)) {
++ if (!strncmp(clone->reg_callid, callid, strlen(callid))) {
++ // ast_log(LOG_NOTICE, "clone->reg_callid %s, req->callid %s found in subpeer\n", clone->reg_callid, callid);
++ found++;
++ peer = clone;
++ break;
++ }
++ }
++ }
++ }
++ if (!found) {
++ // ast_log(LOG_NOTICE, "did not find callid in peer or subpeer\n");
++ /* choose the next best peer or subpeer (that means: find the peer with the smalles expiry time */
++ if (peer->expire == -1) {
++ recycle_peer = peer;
++ // ast_log(LOG_NOTICE, "peer %s expiry %d\n", peer->name, peer->expire);
++ } else {
++ for (i=0; i<peer->max_regs - 1; i++) {
++ snprintf(clone_name, sizeof(clone_name), "%s@%d", peer->name, i);
++ clone = find_peer(clone_name, NULL, 1);
++ if (clone) {
++ if (clone->expire == -1) {
++ recycle_peer = clone;
++ break;
++ }
++ // ast_log(LOG_NOTICE, "clone %s expiry %d\n", clone->name, clone->expire);
++ }
++ }
++ }
++ if (recycle_peer) {
++ peer = recycle_peer;
++ ast_copy_string(peer_name, peer->name, sizeof(peer_name));
++ // ast_log(LOG_NOTICE, "recycling peer %s\n", peer->name);
++ if (peer->subpeer) {
++ i = strchr(peer_name, '@') - peer_name;
++ if (i < sizeof(peer_name))
++ peer_name[i] = '\0';
++ // ast_log(LOG_NOTICE, "i = %d\n", i);
++ }
++ } else {
++ /* deny registration */
++ peer_name[0] = '\0';
++ }
++ }
++ }
+ ast_copy_flags(p, peer, SIP_NAT);
+ transmit_response(p, "100 Trying", req);
+- if (!(res = check_auth(p, req, p->randdata, sizeof(p->randdata), peer->name, peer->secret, peer->md5secret, SIP_REGISTER, uri, 0, ignore))) {
++ if (!(res = check_auth(p, req, p->randdata, sizeof(p->randdata), peer_name, peer->secret, peer->md5secret, SIP_REGISTER, uri, 0, ignore))) {
+ sip_cancel_destroy(p);
+ switch (parse_register_contact(p, peer, req)) {
+ case PARSE_REGISTER_FAILED:
+@@ -6527,6 +6630,7 @@
+ transmit_response_with_date(p, "200 OK", req);
+ peer->lastmsgssent = -1;
+ res = 0;
++ ast_copy_string(peer->reg_callid, callid, sizeof(peer->reg_callid));
+ break;
+ }
+ }
+@@ -6872,6 +6976,11 @@
+ /* XXX The refer_to could contain a call on an entirely different machine, requiring an
+ INVITE with a replaces header -anthm XXX */
+ /* The only way to find out is to use the dialplan - oej */
++ ast_copy_string(sip_pvt->refer_to, refer_to, sizeof(sip_pvt->refer_to));
++ ast_copy_string(sip_pvt->referred_by, referred_by, sizeof(sip_pvt->referred_by));
++ ast_copy_string(sip_pvt->refer_contact, h_contact, sizeof(sip_pvt->refer_contact));
++ ast_copy_string(sip_pvt->refer_replaces, replace_callid, sizeof(sip_pvt->referred_by));
++ return 2;
+ }
+ } else if (ast_exists_extension(NULL, transfercontext, refer_to, 1, NULL) || !strcmp(refer_to, ast_parking_ext())) {
+ /* This is an unsupervised transfer (blind transfer) */
+@@ -7592,6 +7701,8 @@
+ int peers_offline = 0;
+ char *id;
+ char idtext[256] = "";
++ char *tmp;
++ int i = 0;
+
+ if (s) { /* Manager - get ActionID */
+ id = astman_get_header(m,"ActionID");
+@@ -7634,6 +7745,7 @@
+ else
+ ast_copy_string(name, iterator->name, sizeof(name));
+
++ if ((iterator->expire != -1) || (iterator->subpeer != 1)) {
+ pstatus = peer_status(iterator, status, sizeof(status));
+ if (pstatus)
+ peers_online++;
+@@ -7650,14 +7762,24 @@
+ }
+ }
+
+- snprintf(srch, sizeof(srch), FORMAT, name,
++ }
++ /* multiple registration, peer used ? */
++ if ((iterator->expire != -1) || (iterator->subpeer != 1)) {
++ snprintf(srch, sizeof(srch), FORMAT, name,
+ iterator->addr.sin_addr.s_addr ? ast_inet_ntoa(iabuf, sizeof(iabuf), iterator->addr.sin_addr) : "(Unspecified)",
+ ast_test_flag(&iterator->flags_page2, SIP_PAGE2_DYNAMIC) ? " D " : " ", /* Dynamic or not? */
+ (ast_test_flag(iterator, SIP_NAT) & SIP_NAT_ROUTE) ? " N " : " ", /* NAT=yes? */
+ iterator->ha ? " A " : " ", /* permit/deny */
+ ntohs(iterator->addr.sin_port), status);
++ }
+
+ if (!s) {/* Normal CLI list */
++ if ((iterator->expire != -1) || (iterator->subpeer != 1)) {
++ if (iterator->subpeer == 1) {
++ tmp = strchr(name, '@');
++ i = tmp - name;
++ name[i] = '\0';
++ }
+ ast_cli(fd, FORMAT, name,
+ iterator->addr.sin_addr.s_addr ? ast_inet_ntoa(iabuf, sizeof(iabuf), iterator->addr.sin_addr) : "(Unspecified)",
+ ast_test_flag(&iterator->flags_page2, SIP_PAGE2_DYNAMIC) ? " D " : " ", /* Dynamic or not? */
+@@ -7665,6 +7787,7 @@
+ iterator->ha ? " A " : " ", /* permit/deny */
+
+ ntohs(iterator->addr.sin_port), status);
++ }
+ } else { /* Manager format */
+ /* The names here need to be the same as other channels */
+ ast_cli(fd,
+@@ -7690,7 +7813,9 @@
+
+ ASTOBJ_UNLOCK(iterator);
+
+- total_peers++;
++ if ((iterator->expire != -1) || (iterator->subpeer != 1)) {
++ total_peers++;
++ }
+ } while(0) );
+
+ if (!s) {
+@@ -8725,6 +8850,7 @@