Index: include/asterisk/res_fax.h
===================================================================
--- include/asterisk/res_fax.h	(revision 332655)
+++ include/asterisk/res_fax.h	(working copy)
@@ -172,6 +172,8 @@
 	struct ast_fax_t38_parameters their_t38_parameters;
 	/*! the id of the t.38 gateway framehook for this channel */
 	int gateway_id;
+	/*! the timeout for this gateway in seconds */
+	int gateway_timeout;
 };
 
 struct ast_fax_tech;
Index: res/res_fax.c
===================================================================
--- res/res_fax.c	(revision 332655)
+++ res/res_fax.c	(working copy)
@@ -186,6 +186,9 @@
 					<enum name="gateway">
 						<para>R/W T38 Gateway Enabled (yes/no)</para>
 					</enum>
+					<enum name="timeout">
+						<para>R/W Gateway timeout in seconds (yes/no/seconds)</para>
+					</enum>
 					<enum name="pages">
 						<para>R/O Number of pages transferred.</para>
 					</enum>
@@ -467,6 +470,7 @@
 	d->minrate = general_options.minrate;
 	d->maxrate = general_options.maxrate;
 	d->gateway_id = -1;
+	d->gateway_timeout = FAX_GATEWAY_TIMEOUT;
 
 	return d;
 }
@@ -2507,7 +2511,7 @@
 	ast_dsp_set_faxmode(gateway->peer_dsp, DSP_FAXMODE_DETECT_V21);
 
 	details->caps = AST_FAX_TECH_GATEWAY;
-	if (!(gateway->s = fax_session_reserve(details, &gateway->token))) {
+	if (details->gateway_timeout && !(gateway->s = fax_session_reserve(details, &gateway->token))) {
 		details->caps |= ~AST_FAX_TECH_GATEWAY;
 		ast_log(LOG_ERROR, "Can't reserve a FAX session, gateway attempt failed.\n");
 		ao2_ref(gateway, -1);
@@ -2591,6 +2595,7 @@
 
 	gateway->t38_state = T38_STATE_NEGOTIATING;
 	gateway->timeout_start = ast_tvnow();
+	details->gateway_timeout = FAX_GATEWAY_TIMEOUT;
 
 	ast_debug(1, "requesting T.38 for gateway session for %s\n", chan->name);
 	return fp;
@@ -2683,6 +2688,7 @@
 			t38_parameters_ast_to_fax(&details->their_t38_parameters, control_params);
 			gateway->t38_state = T38_STATE_UNKNOWN;
 			gateway->timeout_start = ast_tvnow();
+			details->gateway_timeout = FAX_GATEWAY_TIMEOUT;
 			ao2_ref(details, -1);
 			return f;
 		} else if (state == T38_STATE_UNAVAILABLE || state == T38_STATE_REJECTED) {
@@ -2720,6 +2726,7 @@
 			t38_parameters_ast_to_fax(&details->their_t38_parameters, control_params);
 			gateway->t38_state = T38_STATE_UNKNOWN;
 			gateway->timeout_start = ast_tvnow();
+			details->gateway_timeout = FAX_GATEWAY_TIMEOUT;
 
 			ast_debug(1, "%s is attempting to negotiate T.38 after we already sent a negotiation request based on v21 preamble detection\n", active->name);
 			ao2_ref(details, -1);
@@ -2898,10 +2905,23 @@
 static struct ast_frame *fax_gateway_framehook(struct ast_channel *chan, struct ast_frame *f, enum ast_framehook_event event, void *data) {
 	struct fax_gateway *gateway = data;
 	struct ast_channel *peer, *active;
+	struct ast_fax_session_details *details;
 
+	if (gateway->s) {
+		details = gateway->s->details;
+		ao2_ref(details, 1);
+	} else {
+		if (!(details = find_details(chan))) {
+			ast_log(LOG_ERROR, "no FAX session details found on chan %s for T.38 gateway session, odd\n", chan->name);
+			ast_framehook_detach(chan, gateway->framehook);
+			details->gateway_id = -1;
+			return f;
+		}
+	}
+
 	/* restore audio formats when we are detached */
 	if (event == AST_FRAMEHOOK_EVENT_DETACHED) {
-		set_channel_variables(chan, gateway->s->details);
+		set_channel_variables(chan, details);
 
 		if (gateway->bridged) {
 			ast_set_read_format(chan, gateway->chan_read_format);
@@ -2914,20 +2934,24 @@
 			}
 		}
 
+		ao2_ref(details, -1);
 		return NULL;
 	}
 
 	if (!f || (event == AST_FRAMEHOOK_EVENT_ATTACHED)) {
+		ao2_ref(details, -1);
 		return NULL;
 	};
 
 	/* this frame was generated by the fax gateway, pass it on */
 	if (ast_test_flag(f, AST_FAX_FRFLAG_GATEWAY)) {
+		ao2_ref(details, -1);
 		return f;
 	}
 
 	if (!(peer = ast_bridged_channel(chan))) {
 		/* not bridged, don't do anything */
+		ao2_ref(details, -1);
 		return f;
 	}
 
@@ -2936,16 +2960,19 @@
 		if (ast_channel_get_t38_state(chan) == T38_STATE_UNAVAILABLE && ast_channel_get_t38_state(peer) == T38_STATE_UNAVAILABLE) {
 			ast_debug(1, "not starting gateway for %s and %s; neither channel supports T.38\n", chan->name, peer->name);
 			ast_framehook_detach(chan, gateway->framehook);
-			gateway->s->details->gateway_id = -1;
+			details->gateway_id = -1;
 
-			ast_string_field_set(gateway->s->details, result, "FAILED");
-			ast_string_field_set(gateway->s->details, resultstr, "neither channel supports T.38");
-			ast_string_field_set(gateway->s->details, error, "T38_NEG_ERROR");
-			set_channel_variables(chan, gateway->s->details);
+			ast_string_field_set(details, result, "FAILED");
+			ast_string_field_set(details, resultstr, "neither channel supports T.38");
+			ast_string_field_set(details, error, "T38_NEG_ERROR");
+			set_channel_variables(chan, details);
+			ao2_ref(details, -1);
 			return f;
 		}
 
-		gateway->timeout_start = ast_tvnow();
+		if (details->gateway_timeout) {
+			gateway->timeout_start = ast_tvnow();
+		}
 
 		/* we are bridged, change r/w formats to SLIN for v21 preamble
 		 * detection and T.30 */
@@ -2966,15 +2993,16 @@
 	}
 
 	if (gateway->bridged && !ast_tvzero(gateway->timeout_start)) {
-		if (ast_tvdiff_ms(ast_tvnow(), gateway->timeout_start) > FAX_GATEWAY_TIMEOUT) {
+		if (ast_tvdiff_ms(ast_tvnow(), gateway->timeout_start) > details->gateway_timeout) {
 			ast_debug(1, "no fax activity between %s and %s after %d ms, disabling gateway\n", chan->name, peer->name, FAX_GATEWAY_TIMEOUT);
 			ast_framehook_detach(chan, gateway->framehook);
-			gateway->s->details->gateway_id = -1;
+			details->gateway_id = -1;
 
-			ast_string_field_set(gateway->s->details, result, "FAILED");
-			ast_string_field_build(gateway->s->details, resultstr, "no fax activity after %d ms", FAX_GATEWAY_TIMEOUT);
-			ast_string_field_set(gateway->s->details, error, "TIMEOUT");
-			set_channel_variables(chan, gateway->s->details);
+			ast_string_field_set(details, result, "FAILED");
+			ast_string_field_build(details, resultstr, "no fax activity after %d ms", FAX_GATEWAY_TIMEOUT);
+			ast_string_field_set(details, error, "TIMEOUT");
+			set_channel_variables(chan, details);
+			ao2_ref(details, -1);
 			return f;
 		}
 	}
@@ -2988,6 +3016,7 @@
 		case AST_FORMAT_ULAW:
 			break;
 		default:
+			ao2_ref(details, -1);
 			return f;
 		}
 		break;
@@ -2995,13 +3024,16 @@
 		if (f->subclass.integer == AST_MODEM_T38) {
 			break;
 		}
+		ao2_ref(details, -1);
 		return f;
 	case AST_FRAME_CONTROL:
 		if (f->subclass.integer == AST_CONTROL_T38_PARAMETERS) {
 			break;
 		}
+		ao2_ref(details, -1);
 		return f;
 	default:
+		ao2_ref(details, -1);
 		return f;
 	}
 
@@ -3015,17 +3047,20 @@
 		break;
 	default:
 		ast_log(LOG_WARNING, "unhandled framehook event %i\n", event);
+		ao2_ref(details, -1);
 		return f;
 	}
 
 	/* handle control frames */
 	if (f->frametype == AST_FRAME_CONTROL && f->subclass.integer == AST_CONTROL_T38_PARAMETERS) {
+		ao2_ref(details, -1);
 		return fax_gateway_detect_t38(gateway, chan, peer, active, f);
 	}
 
 	if (!gateway->detected_v21 && gateway->t38_state == T38_STATE_UNAVAILABLE && f->frametype == AST_FRAME_VOICE) {
 		/* not in gateway mode and have not detected v21 yet, listen
 		 * for v21 */
+		ao2_ref(details, -1);
 		return fax_gateway_detect_v21(gateway, chan, peer, active, f);
 	}
 
@@ -3036,6 +3071,7 @@
 		if ((f->frametype == AST_FRAME_VOICE) && (f->subclass.codec != AST_FORMAT_SLINEAR)) {
 			if (active->readtrans && (f = ast_translate(active->readtrans, f, 1)) == NULL) {
 				f = &ast_null_frame;
+				ao2_ref(details, -1);
 				return f;
 			}
 		}
@@ -3046,6 +3082,7 @@
 		 * now we'll just ignore the return value. */
 		gateway->s->tech->write(gateway->s, f);
 		f = &ast_null_frame;
+		ao2_ref(details, -1);
 		return f;
 	}
 
@@ -3062,12 +3099,15 @@
 			};
 			memset(silence_buf, 0, sizeof(silence_buf));
 
+			ao2_ref(details, -1);
 			return ast_frisolate(&silence_frame);
 		} else {
+			ao2_ref(details, -1);
 			return &ast_null_frame;
 		}
 	}
 
+	ao2_ref(details, -1);
 	return f;
 }
 
@@ -3709,6 +3749,8 @@
 	} else if (!strcasecmp(data, "t38gateway") || !strcasecmp(data, "gateway") ||
 		   !strcasecmp(data, "t38_gateway") || !strcasecmp(data, "faxgateway")) {
 		ast_copy_string(buf, details->gateway_id != -1 ? "yes" : "no", len);
+	} else if (!strcasecmp(data, "timeout")) {
+		snprintf(buf, len, "%d", details->gateway_timeout / 1000);
 	} else if (!strcasecmp(data, "error")) {
 		ast_copy_string(buf, details->error, len);
 	} else if (!strcasecmp(data, "filename")) {
@@ -3804,6 +3846,18 @@
 		} else {
 			ast_log(LOG_WARNING, "Unsupported value '%s' passed to FAXOPT(%s).\n", value, data);
 		}
+	} else if (!strcasecmp(data, "timeout")) {
+		const char *val = ast_skip_blanks(value);
+		int timeout;
+		if (ast_true(val)) {
+			details->gateway_timeout = FAX_GATEWAY_TIMEOUT;
+		} else if (ast_false(val)) {
+			details->gateway_timeout = 0;
+		} else if (sscanf(val, "%d", &timeout) == 1 && timeout > 0) {
+			details->gateway_timeout = timeout * 1000;
+		} else {
+			ast_log(LOG_WARNING, "Unsupported value '%s' passed to FAXOPT(%s).\n", value, data);
+		}
 	} else if (!strcasecmp(data, "headerinfo")) {
 		ast_string_field_set(details, headerinfo, value);
 	} else if (!strcasecmp(data, "localstationid")) {
