diff --git a/channels/chan_brcm.c b/channels/chan_brcm.c
index d806b74a4c2327399a5389da4a49fe04bbd041a3..fe5cc6319ab16d63b5118255624c8da434650ff2 100644
--- a/channels/chan_brcm.c
+++ b/channels/chan_brcm.c
@@ -84,6 +84,10 @@ static int brcm_unmute_connection(struct brcm_subchannel *p);
 static int brcm_close_connection(struct brcm_subchannel *p);
 static int brcm_create_conference(struct brcm_pvt *p);
 static int brcm_stop_conference(struct brcm_subchannel *p);
+static void brcm_attended_call_transfer(struct brcm_subchannel *sub, struct brcm_subchannel *sub_peer,
+		struct ast_channel *owner, struct ast_channel *peer_owner);
+static void brcm_unattended_call_transfer(struct brcm_subchannel *sub, struct brcm_subchannel *sub_peer,
+		struct ast_channel *owner, struct ast_channel *peer_owner);
 static int brcm_finish_transfer(struct ast_channel *owner, struct brcm_subchannel *p, int result);
 static int brcm_call(struct ast_channel *ast, const char *dest, int timeout);
 static int brcm_devicestate(const char *device_number);
@@ -2097,6 +2101,249 @@ void handle_dtmf_calling(struct brcm_subchannel *sub)
 	}
 }
 
+// Hangup ALL brcm lines currently ringing with busy casue.
+static int brcm_busy_all_ringers(void)
+{
+	struct brcm_pvt *pvt;
+	int i;
+
+	brcm_lock_pvts();
+	pvt = iflist;
+
+	while(pvt) {
+		for (i=0; i<NUM_SUBCHANNELS; i++) {
+			if (pvt->sub[i] && pvt->sub[i]->owner && pvt->sub[i]->channel_state == RINGING) {
+				ast_debug(4, "Hangup BUSY on %s\n", ast_channel_name(pvt->sub[i]->owner));
+				ast_queue_control(pvt->sub[i]->owner, AST_CONTROL_BUSY);
+				ast_queue_hangup_with_cause(pvt->sub[i]->owner, AST_CAUSE_USER_BUSY);
+			}
+		}
+
+		pvt = brcm_get_next_pvt(pvt);
+	}
+
+	brcm_unlock_pvts();
+
+	return 0;
+}
+
+static void handle_Rnumber_etsi(struct brcm_subchannel *sub, struct brcm_subchannel *sub_peer,
+		struct ast_channel *owner, struct ast_channel *peer_owner)
+{
+	struct brcm_pvt *p = sub->parent;
+
+	switch (p->dtmf_first) {
+		/* Force busy on waiting call or hang up call on hold */
+		case '0':
+			if (sub->channel_state == INCALL && sub_peer->channel_state == CALLWAITING) {
+				ast_debug(2, "Sending busy to waiting call\n");
+
+				/* Immediately send busy next time someone calls us during this call */
+				//sub->cw_rejected = 1;
+
+				if (ast_sched_del(sched, sub_peer->cw_timer_id)) {
+					ast_log(LOG_WARNING, "Failed to remove scheduled call waiting timer\n");
+				}
+				sub_peer->cw_timer_id = -1;
+
+				ast_queue_control(peer_owner, AST_CONTROL_BUSY);
+				brcm_busy_all_ringers();
+				ast_indicate(owner, AST_CONTROL_UNHOLD);
+			} else if (sub->channel_state == INCALL && sub_peer->channel_state == ONHOLD) {
+				ast_debug(2, "Hanging up call on hold\n");
+
+				sub_peer = brcm_get_onhold_subchannel(p);
+
+				ast_queue_control(peer_owner, AST_CONTROL_HANGUP);
+				sub_peer->channel_state = CALLENDED;
+				brcm_close_connection(sub_peer);
+			}
+			break;
+		/* Hangup current call and answer waiting call */
+		case '1':
+			if (sub->channel_state == INCALL && (sub_peer->channel_state == CALLWAITING || sub_peer->channel_state == ONHOLD)) {
+
+				/* Close connection and hangup active subchannel */
+				if (owner) {
+					ast_queue_control(owner, AST_CONTROL_HANGUP);
+				}
+				sub->channel_state = CALLENDED;
+				brcm_close_connection(sub);
+
+				if (sub_peer->channel_state == CALLWAITING) {
+					ast_log(LOG_WARNING, "R1 call waiting\n");
+					/* Stop call waiting tone on current call */
+					brcm_stop_callwaiting(p);
+
+					if (ast_sched_del(sched, sub_peer->cw_timer_id)) {
+						ast_log(LOG_WARNING, "Failed to remove scheduled call waiting timer\n");
+					}
+					sub_peer->cw_timer_id = -1;
+
+					/* Pick up call waiting */
+					if (!sub_peer->connection_init) {
+						ast_debug(9, "create_connection()\n");
+						brcm_create_connection(sub_peer);
+					}
+					if (peer_owner) {
+						ast_queue_control(peer_owner, AST_CONTROL_ANSWER);
+						sub_peer->channel_state = INCALL;
+					}
+				} else if (sub_peer->channel_state == ONHOLD) {
+					ast_log(LOG_WARNING, "R1 Unholding\n");
+
+					/* Unhold inactive subchannel */
+					if (peer_owner) {
+						brcm_unmute_connection(sub_peer);
+						ast_queue_unhold(peer_owner);
+						sub_peer->channel_state = INCALL;
+					}
+				}
+			}
+			break;
+		/* Answer waiting call and put other call on hold (switch calls) */
+		case '2':
+			if (sub->channel_state == INCALL && (sub_peer->channel_state == CALLWAITING || sub_peer->channel_state == ONHOLD)) {
+
+				brcm_mute_connection(sub);
+				if (owner) {
+					ast_queue_hold(owner, NULL);
+				}
+
+				if (sub_peer->channel_state == CALLWAITING) {
+					ast_log(LOG_WARNING, "R2 Call waiting\n");
+
+					/* Stop call waiting tone on current call */
+					brcm_stop_callwaiting(p);
+
+					/* Cancel timer */
+					if (ast_sched_del(sched, sub_peer->cw_timer_id)) {
+						ast_log(LOG_WARNING, "Failed to remove scheduled call waiting timer\n");
+					}
+					sub_peer->cw_timer_id = -1;
+
+					if (ast_sched_del(sched, sub_peer->cwBeep_timer_id)) {
+						ast_log(LOG_WARNING, "Failed to remove scheduled call waiting beep timer\n");
+					}
+					sub_peer->cwBeep_timer_id = -1;
+
+					/* Pick up call waiting */
+					if (!sub_peer->connection_init) {
+						ast_debug(9, "create_connection()\n");
+						brcm_create_connection(sub_peer);
+					}
+					if (peer_owner) {
+						ast_queue_control(peer_owner, AST_CONTROL_ANSWER);
+						sub_peer->channel_state = INCALL;
+					}
+				} else if (sub_peer->channel_state == ONHOLD) {
+					ast_log(LOG_WARNING, "R2 on hold\n");
+
+					/* Unhold inactive subchannel */
+					if (peer_owner) {
+						brcm_unmute_connection(sub_peer);
+						ast_queue_unhold(peer_owner);
+						sub_peer->channel_state = INCALL;
+					}
+				}
+
+				sub->channel_state = ONHOLD;
+			}
+			break;
+		/* Connect waiting call to existing call to create 3-way */
+		case '3':
+			if (sub->channel_state == INCALL && sub_peer->channel_state == ONHOLD) {
+				ast_debug(2, "DTMF3 after HF\n");
+				brcm_create_conference(p);
+			}
+			break;
+		/* Remote transfer held call to active call */
+		case '4':
+			brcm_attended_call_transfer(sub, sub_peer, owner, peer_owner);
+			break;
+		case '5':
+			brcm_unattended_call_transfer(sub, sub_peer, owner, peer_owner);
+			break;
+		default:
+			ast_log(LOG_NOTICE, "Unhandled DTMF %c\n", p->dtmfbuf[0]);
+			break;
+	}
+}
+
+static void handle_Rnumber_uk(struct brcm_subchannel *sub, struct brcm_subchannel *sub_peer,
+		struct ast_channel *owner, struct ast_channel *peer_owner)
+{
+	struct brcm_pvt *p = sub->parent;
+
+	switch (p->dtmf_first) {
+		case '4':
+			brcm_attended_call_transfer(sub, sub_peer, owner, peer_owner);
+			break;
+		case '5':
+			brcm_unattended_call_transfer(sub, sub_peer, owner, peer_owner);
+			break;
+		default:
+			ast_log(LOG_ERROR, "Unhandled DTMF %c\n", p->dtmfbuf[0]);
+			break;
+	}
+}
+
+static void handle_Rkey_uk(struct brcm_subchannel *sub, struct brcm_subchannel *sub_peer,
+		struct ast_channel *owner, struct ast_channel *peer_owner)
+{
+	struct brcm_pvt *p = sub->parent;
+
+	if (sub->channel_state == INCALL && (sub_peer->channel_state == CALLWAITING || sub_peer->channel_state == ONHOLD)) {
+		brcm_mute_connection(sub);
+		if (sub_peer->channel_state == CALLWAITING) {
+			if (owner) {
+				ast_queue_hold(owner, NULL);
+			}
+			ast_log(LOG_NOTICE, " R in Call waiting\n");
+			/* Cancel timers */
+			if (ast_sched_del(sched, sub_peer->cw_timer_id)) {
+				ast_log(LOG_WARNING, "Failed to remove scheduled call waiting timer\n");
+			}
+			sub_peer->cw_timer_id = -1;
+			if (ast_sched_del(sched, sub_peer->cwBeep_timer_id)) {
+				ast_log(LOG_WARNING, "Failed to remove scheduled call waiting beep timer\n");
+			}
+			sub_peer->cwBeep_timer_id = -1;
+			/* Pick up call waiting */
+			if (!sub_peer->connection_init) {
+				ast_debug(9, "create_connection()\n");
+				brcm_create_connection(sub_peer);
+			}
+			if (peer_owner) {
+				ast_queue_control(peer_owner, AST_CONTROL_ANSWER);
+				sub_peer->channel_state = INCALL;
+				sub_peer->call_direction = INCOMING_CALL;
+				sub->channel_state = ONHOLD;
+			}
+		} else if (sub_peer->channel_state == ONHOLD) {
+			ast_log(LOG_NOTICE, "R on hold, line: %d action: %s\n",
+				p->line_id, sub->call_direction == INCOMING_CALL ? "Toggle" : "3way Conference");
+			if (sub->call_direction == OUTGOING_CALL) {
+				sub->channel_state = INCALL;
+				sub->conf_timer_id = ast_sched_add(sched, dtmf_wait_timer, setup_conference_call_cb, p);
+			} else if (sub->call_direction == INCOMING_CALL){
+				brcm_unmute_connection(sub_peer);
+				ast_queue_unhold(peer_owner);
+				sub_peer->channel_state = INCALL;
+
+				brcm_mute_connection(sub);
+				ast_queue_hold(owner, NULL);
+				sub->channel_state = ONHOLD;
+			}
+		}
+	} else if ((sub->channel_state == DIALING || sub->channel_state == OFFHOOK || sub->channel_state == RINGBACK) &&
+			sub_peer->channel_state != ONHOLD) {
+		ast_log(LOG_NOTICE, "R while offhook/dialing\n");
+		brcm_cancel_dialing_timeouts(p);
+		brcm_reset_dtmf_buffer(p);
+		p->hf_detected = 0;
+	}
+}
 /*
  * Perform actions for hook flash.
  * Preconditions: One subchannel should be in CALLWAITING or ONHOLD,
@@ -2111,7 +2358,8 @@ static void handle_hookflash(struct brcm_subchannel *sub, struct brcm_subchannel
 	struct ast_bridge *bridge;
 	struct ast_bridge_channel *bridge_channel;
 
-	ast_log(LOG_NOTICE, "Hook Flash detected for phone line %d, p->dtmf_first = %d\r\n", sub->parent->line_id, p->dtmf_first);
+	ast_log(LOG_NOTICE, "Hook Flash detected for phone line %d, p->dtmf_first = %d, flashSpec: %d\r\n", sub->parent->line_id, p->dtmf_first,
+		channel_config[p->line_id].flashSpec);
 
 	if (owner) {
 		bridge = ast_channel_internal_bridge(owner);
@@ -2132,7 +2380,7 @@ static void handle_hookflash(struct brcm_subchannel *sub, struct brcm_subchannel
 	}
 
 	if (p->dtmf_first < 0) {
-		ast_log(LOG_NOTICE, "sub->channel_state = %d, sub_peer->channel_state = %d\n", sub->channel_state, sub_peer->channel_state);
+		ast_log(LOG_NOTICE, "sub->channel_state = %s, sub_peer->channel_state = %s\n", state2str(sub->channel_state), state2str(sub_peer->channel_state));
 		/* If current subchannel is in call and peer subchannel is idle, provide dialtone */
 		if (sub->channel_state == INCALL && (sub_peer->channel_state == ONHOOK || sub_peer->channel_state == CALLENDED)) {
 			ast_debug(2, "R while in call and idle peer subchannel\n");
@@ -2219,159 +2467,21 @@ static void handle_hookflash(struct brcm_subchannel *sub, struct brcm_subchannel
 				brcm_send_ubus_event("CALL_UNHOLD",p->line_id);
 				sub_peer->channel_state = INCALL;
 			}
-		} else if (sub->channel_state == INCALL && (sub_peer->channel_state == CALLWAITING || sub_peer->channel_state == ONHOLD)) {
-			brcm_mute_connection(sub);
-			if (sub_peer->channel_state == CALLWAITING) {
-				if (owner) {
-					ast_queue_hold(owner, NULL);
-				}
-				ast_log(LOG_NOTICE, " R in Call waiting\n");
-				/* Cancel timers */
-				if (ast_sched_del(sched, sub_peer->cw_timer_id)) {
-					ast_log(LOG_WARNING, "Failed to remove scheduled call waiting timer\n");
-				}
-				sub_peer->cw_timer_id = -1;
-				if (ast_sched_del(sched, sub_peer->cwBeep_timer_id)) {
-					ast_log(LOG_WARNING, "Failed to remove scheduled call waiting beep timer\n");
-				}
-				sub_peer->cwBeep_timer_id = -1;
-				/* Pick up call waiting */
-				if (!sub_peer->connection_init) {
-					ast_debug(9, "create_connection()\n");
-					brcm_create_connection(sub_peer);
-				}
-				if (peer_owner) {
-					ast_queue_control(peer_owner, AST_CONTROL_ANSWER);
-					sub_peer->channel_state = INCALL;
-					sub_peer->call_direction = INCOMING_CALL;
-					sub->channel_state = ONHOLD;
-				}
-			} else if (sub_peer->channel_state == ONHOLD) {
-				ast_log(LOG_NOTICE, "R on hold, line: %d direction of 2nd call is %s\n",
-					p->line_id, sub->call_direction == INCOMING_CALL ? "incoming" : "outgoing");
-				if (sub->call_direction == OUTGOING_CALL) {
-					sub->channel_state = INCALL;
-					sub->conf_timer_id = ast_sched_add(sched, dtmf_wait_timer, setup_conference_call_cb, p);
-				} else if (sub->call_direction == INCOMING_CALL){
-					brcm_unmute_connection(sub_peer);
-					ast_queue_unhold(peer_owner);
-					sub_peer->channel_state = INCALL;
-
-					brcm_mute_connection(sub);
-					ast_queue_hold(owner, NULL);
-					sub->channel_state = ONHOLD;
-				}
-			}
-		} else if ((sub->channel_state == DIALING || sub->channel_state == OFFHOOK || sub->channel_state == RINGBACK) &&
-				sub_peer->channel_state != ONHOLD) {
-			ast_log(LOG_NOTICE, "R while offhook/dialing\n");
-			brcm_cancel_dialing_timeouts(p);
-			brcm_reset_dtmf_buffer(p);
-			p->hf_detected = 0;
 		} else if (sub->channel_state == RINGBACK && sub_peer->channel_state == ONHOLD) {
 			ast_debug(4, "R during ringback\n");
 			sub->channel_state = INCALL;
 			sub->conf_timer_id = ast_sched_add(sched, dtmf_wait_timer, setup_conference_call_cb, p);
 		}
+
+		if (channel_config[p->line_id].flashSpec == FLASH_SPEC_UK)
+			handle_Rkey_uk(sub, sub_peer, owner, peer_owner);
 	}
 
 	if (p->dtmf_first > 0) {
-		switch (p->dtmf_first) {
-			case '4':
-				if((sub_peer->conf_timer_id != -1) || (sub->conf_timer_id != -1)){
-					ast_log(LOG_NOTICE ,"Setting up a R4 call transfer \n");
-					if(sub_peer->conf_timer_id != -1)
-						if (ast_sched_del(sched, sub_peer->conf_timer_id)) {
-							ast_log(LOG_WARNING, "Failed to remove scheduled conference setup timer\n");
-					}
-					sub_peer->conf_timer_id = -1;
-					if(sub->conf_timer_id != -1)
-						if (ast_sched_del(sched, sub->conf_timer_id)) {
-							ast_log(LOG_WARNING, "Failed to remove scheduled conference setup timer\n");
-					}
-					sub->conf_timer_id = -1;
-
-					if (sub->channel_state == INCALL && sub_peer->channel_state == ONHOLD &&
-							owner && peer_owner) {
-						struct ast_channel *bridged_chan_inactive = ast_channel_bridge_peer(peer_owner);
-						struct ast_channel *bridged_chan_active = ast_channel_bridge_peer(owner);
-						char dest[AST_CHANNEL_NAME * 2] = { '\0', };
-
-						if (bridged_chan_inactive && bridged_chan_active) {
-							// Hold the transfer target by default unless being configured no
-							if (hold_target_before_refer)
-								ast_queue_hold(owner, NULL);
-
-							// Start the transfer by sending REFER to the transferee
-							snprintf(dest, sizeof(dest) - 1, "%s?Replaces=%s",
-									ast_channel_exten(owner), ast_channel_name(bridged_chan_active));
-							ast_debug(1, "Start transfer to [%s] on channel %s\n", dest, ast_channel_name(bridged_chan_active));
-							int res = -1;
-							ast_channel_lock(bridged_chan_inactive);
-							if (!ast_test_flag(ast_channel_flags(bridged_chan_inactive), AST_FLAG_ZOMBIE) &&
-									!ast_check_hangup(bridged_chan_inactive)) {
-								if (ast_channel_tech(bridged_chan_inactive)->transfer) {
-									res = ast_channel_tech(bridged_chan_inactive)->transfer(bridged_chan_inactive, dest);
-									if (res == 0)
-										res = 1;
-								} else
-									res = 0;
-							}
-							ast_channel_unlock(bridged_chan_inactive);
-							if (res < 0) {
-								ast_log(LOG_ERROR, "ast_transfer() failed\n");
-							} else if (res == 0) {
-								ast_log(LOG_ERROR, "ast_transfer() is not supported on the peer channel\n");
-							} else {
-								sub->channel_state = TRANSFERING;
-							}
-						} else {
-							ast_log(LOG_ERROR, "can't get the peer channel\n");
-						}
-					}
-				}
-				else
-					ast_log(LOG_ERROR,"Late R4 ,Ignoring since conference should be set up by now \n");
-				break;
-			case '5':
-				ast_debug(4 ,"R5 unattended call transfer\n");
-				if((sub_peer->conf_timer_id != -1) || (sub->conf_timer_id != -1)) {
-					if(sub->conf_timer_id != -1) {
-						if (ast_sched_del(sched, sub->conf_timer_id))
-							ast_log(LOG_ERROR, "Failed to remove scheduled conference setup timer\n");
-						ast_debug(4, "sub->conf_timer_id deleted\n");
-					}
-					sub->conf_timer_id = -1;
-					if(sub_peer->conf_timer_id != -1) {
-						if (ast_sched_del(sched, sub_peer->conf_timer_id))
-							ast_log(LOG_ERROR, "Failed to remove scheduled conference setup timer\n");
-						ast_debug(4, "sub_peer->conf_timer_id deleted\n");
-					}
-					sub_peer->conf_timer_id = -1;
-
-					channel_settings *s = &channel_config[p->line_id];
-					if (!s->calleridenable) {
-						p->tech->stop_ringing(p);
-					} else {
-						p->tech->stop_ringing_callerid_pending(p);
-					}
-
-					// unattended call transfer: cancel the the call to transfer target
-					if (sub->owner && sub_peer->owner) {
-						strncpy(sub_peer->blind_xfer_target, ast_channel_exten(owner), sizeof(sub->blind_xfer_target) - 1);
-						ast_queue_control(sub->owner, AST_CONTROL_HANGUP);
-						ast_queue_unhold(sub_peer->owner);
-						sub_peer->channel_state = TRANSFERING;
-					}
-				}
-				else
-					ast_log(LOG_ERROR,"Late R5 ,Ignoring since conference should be set up by now \n");
-				break;
-			default:
-				ast_log(LOG_ERROR, "Unhandled DTMF %c\n", p->dtmfbuf[0]);
-				break;
-
-		}
+		if (channel_config[p->line_id].flashSpec == FLASH_SPEC_ETSI)
+			handle_Rnumber_etsi(sub, sub_peer, owner, peer_owner);
+		else
+			handle_Rnumber_uk(sub, sub_peer, owner, peer_owner);
 	}
 	brcm_reset_dtmf_buffer(p);
 }
@@ -3778,7 +3888,7 @@ static channel_settings channel_settings_create(void)
 		.calleridenable = 0, //clip
                 .calleridnameenable = 0,  //cnip
                 .anonymouscallenable = 0, //clir
-
+		.flashSpec = 0,
 	};
 	return line_conf;
 }
@@ -3836,6 +3946,12 @@ static void channel_settings_load(channel_settings *channel_config, struct ast_v
                 else if (!strcasecmp(v->name, "anonymouscallenable")) {
                         channel_config->anonymouscallenable = ast_true(v->value)?1:0;
                 }
+		else if (!strcasecmp(v->name, "flash_spec")) {
+			if (!strcasecmp(v->value, "etsi"))
+				channel_config->flashSpec = FLASH_SPEC_ETSI;
+			else
+				channel_config->flashSpec = FLASH_SPEC_UK;
+                }
 		v = v->next;
 	}
 }
@@ -4776,6 +4892,108 @@ static int brcm_stop_conference(struct brcm_subchannel *p)
 	return 0;
 }
 
+static void brcm_attended_call_transfer(struct brcm_subchannel *sub, struct brcm_subchannel *sub_peer,
+		struct ast_channel *owner, struct ast_channel *peer_owner)
+{
+	struct brcm_pvt *p = sub->parent;
+
+	if( channel_config[p->line_id].flashSpec == FLASH_SPEC_ETSI ||
+	    channel_config[p->line_id].flashSpec == FLASH_SPEC_UK && ((sub_peer->conf_timer_id != -1) || (sub->conf_timer_id != -1))) {
+		ast_log(LOG_NOTICE ,"Setting up attended call transfer \n");
+		if(sub_peer->conf_timer_id != -1)
+			if (ast_sched_del(sched, sub_peer->conf_timer_id)) {
+				ast_log(LOG_WARNING, "Failed to remove scheduled conference setup timer\n");
+		}
+		sub_peer->conf_timer_id = -1;
+		if(sub->conf_timer_id != -1)
+			if (ast_sched_del(sched, sub->conf_timer_id)) {
+				ast_log(LOG_WARNING, "Failed to remove scheduled conference setup timer\n");
+		}
+		sub->conf_timer_id = -1;
+
+		if (sub->channel_state == INCALL && sub_peer->channel_state == ONHOLD &&
+				owner && peer_owner) {
+			struct ast_channel *bridged_chan_inactive = ast_channel_bridge_peer(peer_owner);
+			struct ast_channel *bridged_chan_active = ast_channel_bridge_peer(owner);
+			char dest[AST_CHANNEL_NAME * 2] = { '\0', };
+
+			if (bridged_chan_inactive && bridged_chan_active) {
+				// Hold the transfer target by default unless being configured no
+				if (hold_target_before_refer)
+					ast_queue_hold(owner, NULL);
+
+				// Start the transfer by sending REFER to the transferee
+				snprintf(dest, sizeof(dest) - 1, "%s?Replaces=%s",
+						ast_channel_exten(owner), ast_channel_name(bridged_chan_active));
+				ast_debug(1, "Start transfer to [%s] on channel %s\n", dest, ast_channel_name(bridged_chan_active));
+				int res = -1;
+				ast_channel_lock(bridged_chan_inactive);
+				if (!ast_test_flag(ast_channel_flags(bridged_chan_inactive), AST_FLAG_ZOMBIE) &&
+						!ast_check_hangup(bridged_chan_inactive)) {
+					if (ast_channel_tech(bridged_chan_inactive)->transfer) {
+						res = ast_channel_tech(bridged_chan_inactive)->transfer(bridged_chan_inactive, dest);
+						if (res == 0)
+							res = 1;
+					} else
+						res = 0;
+				}
+				ast_channel_unlock(bridged_chan_inactive);
+				if (res < 0) {
+					ast_log(LOG_ERROR, "ast_transfer() failed\n");
+				} else if (res == 0) {
+					ast_log(LOG_ERROR, "ast_transfer() is not supported on the peer channel\n");
+				} else {
+					sub->channel_state = TRANSFERING;
+				}
+			} else {
+				ast_log(LOG_ERROR, "can't get the peer channel\n");
+			}
+		}
+	}
+	else
+		ast_log(LOG_ERROR,"Late R4 ,Ignoring since conference should be set up by now \n");
+}
+
+static void brcm_unattended_call_transfer(struct brcm_subchannel *sub, struct brcm_subchannel *sub_peer,
+		struct ast_channel *owner, struct ast_channel *peer_owner)
+{
+	struct brcm_pvt *p = sub->parent;
+
+	ast_log(LOG_ERROR ,"flashSpec  sub_peer->conf_timer_id: %d, sub->conf_timer_id: %d\n", sub_peer->conf_timer_id, sub->conf_timer_id);
+	if((sub_peer->conf_timer_id != -1) || (sub->conf_timer_id != -1)) {
+		ast_log(LOG_NOTICE ,"Setting up unattended call transfer \n");
+		if(sub->conf_timer_id != -1) {
+			if (ast_sched_del(sched, sub->conf_timer_id))
+				ast_log(LOG_ERROR, "Failed to remove scheduled conference setup timer\n");
+			ast_debug(4, "sub->conf_timer_id deleted\n");
+		}
+		sub->conf_timer_id = -1;
+		if(sub_peer->conf_timer_id != -1) {
+			if (ast_sched_del(sched, sub_peer->conf_timer_id))
+				ast_log(LOG_ERROR, "Failed to remove scheduled conference setup timer\n");
+			ast_debug(4, "sub_peer->conf_timer_id deleted\n");
+		}
+		sub_peer->conf_timer_id = -1;
+
+		channel_settings *s = &channel_config[p->line_id];
+		if (!s->calleridenable) {
+			p->tech->stop_ringing(p);
+		} else {
+			p->tech->stop_ringing_callerid_pending(p);
+		}
+
+		// unattended call transfer: cancel the the call to transfer target
+		if (sub->owner && sub_peer->owner) {
+			strncpy(sub_peer->blind_xfer_target, ast_channel_exten(owner), sizeof(sub->blind_xfer_target) - 1);
+			ast_queue_control(sub->owner, AST_CONTROL_HANGUP);
+			ast_queue_unhold(sub_peer->owner);
+			sub_peer->channel_state = TRANSFERING;
+		}
+	}
+	else
+		ast_log(LOG_ERROR,"Late R5 ,Ignoring since conference should be set up by now \n");
+}
+
 static int brcm_close_connection(struct brcm_subchannel *sub)
 {
 	struct brcm_pvt *p = sub->parent;
diff --git a/channels/chan_brcm.h b/channels/chan_brcm.h
index 2e52f85919e7b376c8cca250a203e90ecb87e09b..14520b940f9e745975c95bcd5a1f693537b3ebfb 100644
--- a/channels/chan_brcm.h
+++ b/channels/chan_brcm.h
@@ -198,7 +198,10 @@ typedef struct DTMF_CHARNAME_MAP
 } DTMF_CHARNAME_MAP;
 
 
-
+typedef enum flash_spec {
+	FLASH_SPEC_UK = 0,
+	FLASH_SPEC_ETSI,
+} flash_spec;
 
 typedef struct DIALTONE_MAP
 {
@@ -242,6 +245,7 @@ typedef struct {
 	int anonymouscallenable;
         int calleridenable;
         int calleridnameenable;
+	flash_spec flashSpec;
 } channel_settings;