diff --git a/UPGRADE.txt b/UPGRADE.txt
index 8097c4bae75c987d45bdd9c298b7270cf3ac0aec..dda6d66d8d44f19e827eacb35189b804285bef88 100644
--- a/UPGRADE.txt
+++ b/UPGRADE.txt
@@ -18,6 +18,17 @@
 ===
 ===========================================================
 
+T.38 changes in 1.6.0.11, 1.6.1.2, 1.6.2.0:
+
+Beginning with each of these releases in their respective branches,
+Asterisk's internal methods of negotiating T.38 (FAX over IP) sessions
+changed in non-backwards-compatible ways. Any applications that previously
+used AST_CONTROL_T38 control frames will have to be upgraded to use
+AST_CONTROL_T38_PARAMETERS control frames instead; app_fax.c is a good
+example of how to generate and respond to these frames. These changes were
+made to solve significant T.38 interoperability problems between Asterisk
+and various SIP/T.38 endpoints identified by many users of Asterisk.
+
 From 1.6.2 to 1.6.3:
 
 * Asterisk-addons no longer exists as an independent package.  Those modules
diff --git a/apps/app_fax.c b/apps/app_fax.c
index 6c132c16219a54058d22d4e7cccf430fe643af0c..c2156f0df84c6a5a0af62212ffd851a266581289 100644
--- a/apps/app_fax.c
+++ b/apps/app_fax.c
@@ -471,11 +471,12 @@ static int transmit_audio(fax_session *s)
 			if (fr && fr->frametype == AST_FRAME_DTMF && fr->subclass == 'f') {
 				struct ast_control_t38_parameters parameters = { .request_response = AST_T38_REQUEST_NEGOTIATE,
 										 .version = 0,
-										 .max_datagram = 400,
+										 .max_ifp = 800,
 										 .rate = AST_T38_RATE_9600,
 										 .rate_management = AST_T38_RATE_MANAGEMENT_TRANSFERRED_TCF,
 										 .fill_bit_removal = 1,
 										 .transcoding_mmr = 1,
+										 .transcoding_jbig = 1,
 				};
 				ast_debug(1, "Fax tone detected. Requesting T38\n");
 				ast_indicate_data(s->chan, AST_CONTROL_T38_PARAMETERS, &parameters, sizeof(parameters));
@@ -509,20 +510,18 @@ static int transmit_audio(fax_session *s)
 				res = 1;
 				break;
 			} else if (parameters->request_response == AST_T38_REQUEST_NEGOTIATE) {
+				struct ast_control_t38_parameters our_parameters = { .request_response = AST_T38_NEGOTIATED,
+										     .version = 0,
+										     .max_ifp = 800,
+										     .rate = AST_T38_RATE_9600,
+										     .rate_management = AST_T38_RATE_MANAGEMENT_TRANSFERRED_TCF,
+										     .fill_bit_removal = 1,
+										     .transcoding_mmr = 1,
+										     .transcoding_jbig = 1,
+				};
 				ast_debug(1, "T38 request received, accepting\n");
-				if (parameters->version > 0) {
-					/* Only T.38 Version 0 is supported at this time */
-					parameters->version = 0;
-				}
-				if (parameters->max_datagram > 400) {
-					/* Limit incoming datagram size to our default */
-					/* TODO: this need to come from the udptl stack, not be hardcoded */
-					parameters->max_datagram = 400;
-				}
-				/* we only support bit rates up to 9.6kbps */
-				parameters->rate = AST_T38_RATE_9600;
 				/* Complete T38 switchover */
-				ast_indicate_data(s->chan, AST_CONTROL_T38_PARAMETERS, parameters, sizeof(*parameters));
+				ast_indicate_data(s->chan, AST_CONTROL_T38_PARAMETERS, &our_parameters, sizeof(our_parameters));
 				/* Do not break audio loop, wait until channel driver finally acks switchover
 				   with AST_T38_NEGOTIATED */
 			}
@@ -593,7 +592,7 @@ static int transmit_t38(fax_session *s)
 		return -1;
 	}
 
-	t38_set_max_datagram_size(t38state, s->t38parameters.max_datagram);
+	t38_set_max_datagram_size(t38state, s->t38parameters.max_ifp);
 
 	if (s->t38parameters.fill_bit_removal) {
 		t38_set_fill_bit_removal(t38state, TRUE);
diff --git a/channels/chan_sip.c b/channels/chan_sip.c
index 7297da8f0ea2e8cbf009014810a5e3016d8eaf14..29e0f959513e9b51a6be1ca4314bcd9a24266971 100644
--- a/channels/chan_sip.c
+++ b/channels/chan_sip.c
@@ -1511,10 +1511,10 @@ struct sip_auth {
 #define SIP_PAGE2_SUBSCRIBEMWIONLY	(1 << 18)	/*!< GP: Only issue MWI notification if subscribed to */
 #define SIP_PAGE2_IGNORESDPVERSION	(1 << 19)	/*!< GDP: Ignore the SDP session version number we receive and treat all sessions as new */
 
-#define SIP_PAGE2_T38SUPPORT		        (7 << 20)	/*!< GDP: T38 Fax Passthrough Support */
-#define SIP_PAGE2_T38SUPPORT_UDPTL	        (1 << 20)	/*!< GDP: T38 Fax Passthrough Support (no error correction) */
-#define SIP_PAGE2_T38SUPPORT_UDPTL_FEC	        (2 << 20)	/*!< GDP: T38 Fax Passthrough Support (FEC error correction) */
-#define SIP_PAGE2_T38SUPPORT_UDPTL_REDUNDANCY	(4 << 20)	/*!< GDP: T38 Fax Passthrough Support (redundancy error correction) */
+#define SIP_PAGE2_T38SUPPORT		        (7 << 20)	/*!< GDP: T.38 Fax Support */
+#define SIP_PAGE2_T38SUPPORT_UDPTL	        (1 << 20)	/*!< GDP: T.38 Fax Support (no error correction) */
+#define SIP_PAGE2_T38SUPPORT_UDPTL_FEC	        (2 << 20)	/*!< GDP: T.38 Fax Support (FEC error correction) */
+#define SIP_PAGE2_T38SUPPORT_UDPTL_REDUNDANCY	(4 << 20)	/*!< GDP: T.38 Fax Support (redundancy error correction) */
 
 #define SIP_PAGE2_CALL_ONHOLD		(3 << 23)	/*!< D: Call hold states: */
 #define SIP_PAGE2_CALL_ONHOLD_ACTIVE    (1 << 23)       /*!< D: Active hold */
@@ -1538,36 +1538,6 @@ struct sip_auth {
 
 /*@}*/ 
 
-/*! \name SIPflagsT38
-	T.38 set of flags */
-
-/*@{*/ 
-#define T38FAX_FILL_BIT_REMOVAL			(1 << 0)	/*!< Default: 0 (unset)*/
-#define T38FAX_TRANSCODING_MMR			(1 << 1)	/*!< Default: 0 (unset)*/
-#define T38FAX_TRANSCODING_JBIG			(1 << 2)	/*!< Default: 0 (unset)*/
-/* Rate management */
-#define T38FAX_RATE_MANAGEMENT_TRANSFERRED_TCF	(0 << 3)
-#define T38FAX_RATE_MANAGEMENT_LOCAL_TCF	(1 << 3)	/*!< Unset for transferredTCF (UDPTL), set for localTCF (TPKT) */
-/* UDP Error correction */
-#define T38FAX_UDP_EC_NONE			(0 << 4)	/*!< two bits, if unset NO t38UDPEC field in T38 SDP*/
-#define T38FAX_UDP_EC_FEC			(1 << 4)	/*!< Set for t38UDPFEC */
-#define T38FAX_UDP_EC_REDUNDANCY		(2 << 4)	/*!< Set for t38UDPRedundancy */
-/* T38 Spec version */
-#define T38FAX_VERSION				(3 << 6)	/*!< two bits, 2 values so far, up to 4 values max */
-#define T38FAX_VERSION_0			(0 << 6)	/*!< Version 0 */
-#define T38FAX_VERSION_1			(1 << 6)	/*!< Version 1 */
-/* Maximum Fax Rate */
-#define T38FAX_RATE_2400			(1 << 8)	/*!< 2400 bps t38FaxRate */
-#define T38FAX_RATE_4800			(1 << 9)	/*!< 4800 bps t38FaxRate */
-#define T38FAX_RATE_7200			(1 << 10)	/*!< 7200 bps t38FaxRate */
-#define T38FAX_RATE_9600			(1 << 11)	/*!< 9600 bps t38FaxRate */
-#define T38FAX_RATE_12000			(1 << 12)	/*!< 12000 bps t38FaxRate */
-#define T38FAX_RATE_14400			(1 << 13)	/*!< 14400 bps t38FaxRate */
-
-/*!< This is default: NO MMR and JBIG transcoding, NO fill bit removal, transferredTCF TCF, UDP FEC, Version 0 and 9600 max fax rate */
-static int global_t38_capability = T38FAX_VERSION_0 | T38FAX_RATE_2400 | T38FAX_RATE_4800 | T38FAX_RATE_7200 | T38FAX_RATE_9600;
-/*@}*/ 
-
 /*! \brief debugging state
  * We store separately the debugging requests from the config file
  * and requests from the CLI. Debugging is enabled if either is set
@@ -1598,11 +1568,9 @@ enum t38state {
 
 /*! \brief T.38 channel settings (at some point we need to make this alloc'ed */
 struct t38properties {
-	struct ast_flags t38support;	/*!< Flag for udptl, rtp or tcp support for this session */
-	int capability;			/*!< Our T38 capability */
-	int peercapability;		/*!< Peers T38 capability */
-	int jointcapability;		/*!< Supported T38 capability at both ends */
 	enum t38state state;		/*!< T.38 state */
+	struct ast_control_t38_parameters our_parms;
+	struct ast_control_t38_parameters their_parms;
 };
 
 /*! \brief Parameters to know status of transfer */
@@ -4190,7 +4158,7 @@ static int sip_queryoption(struct ast_channel *chan, int option, void *data, int
 		sip_pvt_lock(p);
 
 		/* Now if T38 support is enabled we need to look and see what the current state is to get what we want to report back */
-		if (ast_test_flag(&p->t38.t38support, SIP_PAGE2_T38SUPPORT)) {
+		if (ast_test_flag(&p->flags[1], SIP_PAGE2_T38SUPPORT)) {
 			switch (p->t38.state) {
 			case T38_LOCAL_REINVITE:
 			case T38_PEER_REINVITE:
@@ -4922,57 +4890,12 @@ static void do_setnat(struct sip_pvt *p)
 	}
 }
 
-/*! \brief Helper function which interprets T.38 capabilities and fills a parameters structure in */
-static void fill_t38_parameters(int capabilities, struct ast_control_t38_parameters *parameters, struct sip_pvt *p)
-{
-	if (capabilities & T38FAX_VERSION_0) {
-		parameters->version = 0;
-	} else if (capabilities & T38FAX_VERSION_1) {
-		parameters->version = 1;
-	}
-
-	if (capabilities & T38FAX_RATE_14400) {
-		parameters->rate = AST_T38_RATE_14400;
-	} else if (capabilities & T38FAX_RATE_12000) {
-		parameters->rate = AST_T38_RATE_12000;
-	} else if (capabilities & T38FAX_RATE_9600) {
-		parameters->rate = AST_T38_RATE_9600;
-	} else if (capabilities & T38FAX_RATE_7200) {
-		parameters->rate = AST_T38_RATE_7200;
-	} else if (capabilities & T38FAX_RATE_4800) {
-		parameters->rate = AST_T38_RATE_4800;
-	} else if (capabilities & T38FAX_RATE_2400) {
-		parameters->rate = AST_T38_RATE_2400;
-	}
-
-	if (capabilities & T38FAX_RATE_MANAGEMENT_TRANSFERRED_TCF) {
-		parameters->rate_management = AST_T38_RATE_MANAGEMENT_TRANSFERRED_TCF;
-	} else if (capabilities & T38FAX_RATE_MANAGEMENT_LOCAL_TCF) {
-		parameters->rate_management = AST_T38_RATE_MANAGEMENT_LOCAL_TCF;
-	}
-
-	if (capabilities & T38FAX_FILL_BIT_REMOVAL) {
-		parameters->fill_bit_removal = 1;
-	}
-
-	if (capabilities & T38FAX_TRANSCODING_MMR) {
-		parameters->transcoding_mmr = 1;
-	}
-
-	if (capabilities & T38FAX_TRANSCODING_JBIG) {
-		parameters->transcoding_jbig = 1;
-	}
-
-	parameters->max_datagram = ast_udptl_get_far_max_datagram(p->udptl);
-}
-
 /*! \brief Change the T38 state on a SIP dialog */
 static void change_t38_state(struct sip_pvt *p, int state)
 {
 	int old = p->t38.state;
 	struct ast_channel *chan = p->owner;
-	enum ast_control_t38 message = 0;
-	struct ast_control_t38_parameters parameters = { 0, };
+	struct ast_control_t38_parameters parameters = { .request_response = 0 };
 
 	/* Don't bother changing if we are already in the state wanted */
 	if (old == state)
@@ -4987,21 +4910,21 @@ static void change_t38_state(struct sip_pvt *p, int state)
 
 	/* Given the state requested and old state determine what control frame we want to queue up */
 	if (state == T38_PEER_REINVITE) {
-		message = parameters.request_response = AST_T38_REQUEST_NEGOTIATE;
-		fill_t38_parameters(p->t38.peercapability, &parameters, p);
+		parameters = p->t38.their_parms;
+		parameters.max_ifp = ast_udptl_get_far_max_ifp(p->udptl);
+		parameters.request_response = AST_T38_REQUEST_NEGOTIATE;
 	} else if (state == T38_ENABLED) {
-		message = parameters.request_response = AST_T38_NEGOTIATED;
-		fill_t38_parameters(p->t38.jointcapability, &parameters, p);
+		parameters = p->t38.their_parms;
+		parameters.max_ifp = ast_udptl_get_far_max_ifp(p->udptl);
+		parameters.request_response = AST_T38_NEGOTIATED;
 	} else if (state == T38_DISABLED && old == T38_ENABLED)
-		message = parameters.request_response = AST_T38_TERMINATED;
+		parameters.request_response = AST_T38_TERMINATED;
 	else if (state == T38_DISABLED && old == T38_LOCAL_REINVITE)
-		message = parameters.request_response = AST_T38_REFUSED;
+		parameters.request_response = AST_T38_REFUSED;
 
 	/* Woot we got a message, create a control frame and send it on! */
 	if (parameters.request_response)
 		ast_queue_control_data(chan, AST_CONTROL_T38_PARAMETERS, &parameters, sizeof(parameters));
-	if (message)
-		ast_queue_control_data(chan, AST_CONTROL_T38, &message, sizeof(message));
 
 	if (ast_test_flag(&p->flags[1], SIP_PAGE2_FAX_DETECT) && !p->outgoing_call) {
 		/* fax detection is enabled and this is an incoming call */
@@ -5029,19 +4952,14 @@ static void change_t38_state(struct sip_pvt *p, int state)
 /*! \brief Set the global T38 capabilities on a SIP dialog structure */
 static void set_t38_capabilities(struct sip_pvt *p)
 {
-	p->t38.capability = global_t38_capability;
 	if (p->udptl) {
 		if (ast_test_flag(&p->flags[1], SIP_PAGE2_T38SUPPORT) == SIP_PAGE2_T38SUPPORT_UDPTL_REDUNDANCY) {
                         ast_udptl_set_error_correction_scheme(p->udptl, UDPTL_ERROR_CORRECTION_REDUNDANCY);
-			p->t38.capability |= T38FAX_UDP_EC_REDUNDANCY;
 		} else if (ast_test_flag(&p->flags[1], SIP_PAGE2_T38SUPPORT) == SIP_PAGE2_T38SUPPORT_UDPTL_FEC) {
 			ast_udptl_set_error_correction_scheme(p->udptl, UDPTL_ERROR_CORRECTION_FEC);
-			p->t38.capability |= T38FAX_UDP_EC_FEC;
 		} else if (ast_test_flag(&p->flags[1], SIP_PAGE2_T38SUPPORT) == SIP_PAGE2_T38SUPPORT_UDPTL) {
 			ast_udptl_set_error_correction_scheme(p->udptl, UDPTL_ERROR_CORRECTION_NONE);
-			p->t38.capability |= T38FAX_UDP_EC_NONE;
 		}
-		p->t38.capability |= T38FAX_RATE_MANAGEMENT_TRANSFERRED_TCF;
 	}
 }
 
@@ -5139,9 +5057,7 @@ static int create_addr_from_peer(struct sip_pvt *dialog, struct sip_peer *peer)
 			/* t38pt_udptl was enabled in the peer and not in [general] */
 			dialog->udptl = ast_udptl_new_with_bindaddr(sched, io, 0, bindaddr.sin_addr);
 		}
-		ast_copy_flags(&dialog->t38.t38support, &peer->flags[1], SIP_PAGE2_T38SUPPORT);
 		set_t38_capabilities(dialog);
-		dialog->t38.jointcapability = dialog->t38.capability;
 	} else if (dialog->udptl) {
 		ast_udptl_destroy(dialog->udptl);
 		dialog->udptl = NULL;
@@ -5441,9 +5357,6 @@ static int sip_call(struct ast_channel *ast, char *dest, int timeout)
 	} else {
 		int xmitres;
 
-		p->t38.jointcapability = p->t38.capability;
-		ast_debug(2, "Our T38 capability (%d), joint T38 capability (%d)\n", p->t38.capability, p->t38.jointcapability);
-
 		sip_pvt_lock(p);
 		xmitres = transmit_invite(p, SIP_INVITE, 1, 2);
 		sip_pvt_unlock(p);
@@ -6321,15 +6234,10 @@ static int sip_write(struct ast_channel *ast, struct ast_frame *frame)
 				we simply forget the frames if we get modem frames before the bridge is up.
 				Fax will re-transmit.
 			*/
-			if (ast->_state == AST_STATE_UP) {
-				if (ast_test_flag(&p->flags[1], SIP_PAGE2_T38SUPPORT) && p->t38.state == T38_DISABLED) {
-					if (!p->pendinginvite) {
-						change_t38_state(p, T38_LOCAL_REINVITE);
-						transmit_reinvite_with_sdp(p, TRUE, FALSE);
-					}
-				} else if (p->udptl && p->t38.state == T38_ENABLED) {
-					res = ast_udptl_write(p->udptl, frame);
-				}
+			if ((ast->_state == AST_STATE_UP) &&
+			    p->udptl &&
+			    (p->t38.state == T38_ENABLED)) {
+				res = ast_udptl_write(p->udptl, frame);
 			}
 			sip_pvt_unlock(p);
 		}
@@ -6459,66 +6367,34 @@ static int sip_transfer(struct ast_channel *ast, const char *dest)
 }
 
 /*! \brief Helper function which updates T.38 capability information and triggers a reinvite */
-static void interpret_t38_parameters(struct sip_pvt *p, enum ast_control_t38 request_response, const struct ast_control_t38_parameters *parameters)
+static void interpret_t38_parameters(struct sip_pvt *p, const struct ast_control_t38_parameters *parameters)
 {
-	if (parameters) {
-		if (!parameters->version) {
-			p->t38.capability = p->t38.jointcapability |= T38FAX_VERSION_0;
-		} else if (parameters->version == 1) {
-			p->t38.capability = p->t38.jointcapability |= T38FAX_VERSION_1;
-		}
-
-		if (parameters->rate == AST_T38_RATE_14400) {
-			p->t38.capability = p->t38.jointcapability |= T38FAX_RATE_14400 | T38FAX_RATE_12000 | T38FAX_RATE_9600 | T38FAX_RATE_7200 | T38FAX_RATE_4800 | T38FAX_RATE_2400;
-		} else if (parameters->rate == AST_T38_RATE_12000) {
-			p->t38.capability = p->t38.jointcapability |= T38FAX_RATE_12000 | T38FAX_RATE_9600 | T38FAX_RATE_7200 | T38FAX_RATE_4800 | T38FAX_RATE_2400;
-		} else if (parameters->rate == AST_T38_RATE_9600) {
-			p->t38.capability = p->t38.jointcapability |= T38FAX_RATE_9600 | T38FAX_RATE_7200 | T38FAX_RATE_4800 | T38FAX_RATE_2400;
-		} else if (parameters->rate == AST_T38_RATE_7200) {
-			p->t38.capability = p->t38.jointcapability |= T38FAX_RATE_7200 | T38FAX_RATE_4800 | T38FAX_RATE_2400;
-		} else if (parameters->rate == AST_T38_RATE_4800) {
-			p->t38.capability = p->t38.jointcapability |= T38FAX_RATE_4800 | T38FAX_RATE_2400;
-		} else if (parameters->rate == AST_T38_RATE_2400) {
-			p->t38.capability = p->t38.jointcapability |= T38FAX_RATE_2400;
-		}
-
-		if (parameters->rate_management == AST_T38_RATE_MANAGEMENT_TRANSFERRED_TCF) {
-			p->t38.capability = p->t38.jointcapability |= T38FAX_RATE_MANAGEMENT_TRANSFERRED_TCF;
-		} else if (parameters->rate_management == AST_T38_RATE_MANAGEMENT_LOCAL_TCF) {
-			p->t38.capability = p->t38.jointcapability |= T38FAX_RATE_MANAGEMENT_LOCAL_TCF;
-		}
-
-		if (parameters->fill_bit_removal) {
-			p->t38.capability = p->t38.jointcapability |= T38FAX_FILL_BIT_REMOVAL;
-		} else {
-			p->t38.capability = p->t38.jointcapability &= ~T38FAX_FILL_BIT_REMOVAL;
-		}
-
-		if (parameters->transcoding_mmr) {
-			p->t38.capability = p->t38.jointcapability |= T38FAX_TRANSCODING_MMR;
-		} else {
-			p->t38.capability = p->t38.jointcapability &= ~T38FAX_TRANSCODING_MMR;
-		}
-
-		if (parameters->transcoding_jbig) {
-			p->t38.capability = p->t38.jointcapability |= T38FAX_TRANSCODING_JBIG;
-		} else {
-			p->t38.capability = p->t38.jointcapability &= ~T38FAX_TRANSCODING_JBIG;
-		}
-
-		if (p->udptl && request_response == AST_T38_REQUEST_NEGOTIATE) {
-			ast_udptl_set_local_max_datagram(p->udptl, parameters->max_datagram ? parameters->max_datagram : 400);
-		}
-	}
-
-	switch (request_response) {
+	switch (parameters->request_response) {
 	case AST_T38_NEGOTIATED:
 	case AST_T38_REQUEST_NEGOTIATE:         /* Request T38 */
 		if (p->t38.state == T38_PEER_REINVITE) {
 			AST_SCHED_DEL_UNREF(sched, p->t38id, dialog_unref(p, "when you delete the t38id sched, you should dec the refcount for the stored dialog ptr"));
+			p->t38.our_parms = *parameters;
+			/* modify our parameters to conform to the peer's parameters,
+			 * based on the rules in the ITU T.38 recommendation
+			 */
+			if (!p->t38.their_parms.fill_bit_removal) {
+				p->t38.our_parms.fill_bit_removal = FALSE;
+			}
+			if (!p->t38.their_parms.transcoding_mmr) {
+				p->t38.our_parms.transcoding_mmr = FALSE;
+			}
+			if (!p->t38.their_parms.transcoding_jbig) {
+				p->t38.our_parms.transcoding_jbig = FALSE;
+			}
+			p->t38.our_parms.version = MIN(p->t38.our_parms.version, p->t38.their_parms.version);
+			p->t38.our_parms.rate_management = p->t38.their_parms.rate_management;
+			ast_udptl_set_local_max_ifp(p->udptl, p->t38.our_parms.max_ifp);
 			change_t38_state(p, T38_ENABLED);
 			transmit_response_with_t38_sdp(p, "200 OK", &p->initreq, XMIT_CRITICAL);
-		} else if (ast_test_flag(&p->t38.t38support, SIP_PAGE2_T38SUPPORT) && p->t38.state != T38_ENABLED) {
+		} else if (ast_test_flag(&p->flags[1], SIP_PAGE2_T38SUPPORT) && p->t38.state != T38_ENABLED) {
+			p->t38.our_parms = *parameters;
+			ast_udptl_set_local_max_ifp(p->udptl, p->t38.our_parms.max_ifp);
 			change_t38_state(p, T38_LOCAL_REINVITE);
 			if (!p->pendinginvite) {
 				transmit_reinvite_with_sdp(p, TRUE, FALSE);
@@ -6626,19 +6502,12 @@ static int sip_indicate(struct ast_channel *ast, int condition, const void *data
 		} else
 			res = -1;
 		break;
-	case AST_CONTROL_T38:	/* T38 control frame */
-		if (datalen != sizeof(enum ast_control_t38)) {
-			ast_log(LOG_ERROR, "Invalid datalen for AST_CONTROL_T38. Expected %d, got %d\n", (int)sizeof(enum ast_control_t38), (int)datalen);
-		} else {
-			interpret_t38_parameters(p, *((enum ast_control_t38 *) data), NULL);
-		}
-		break;
 	case AST_CONTROL_T38_PARAMETERS:
 		if (datalen != sizeof(struct ast_control_t38_parameters)) {
-			ast_log(LOG_ERROR, "Invalid datalen for AST_CONTROL_T38_PARAMETERS. Expected %d, got %d\n", (int)sizeof(struct ast_control_t38_parameters), (int)datalen);
+			ast_log(LOG_ERROR, "Invalid datalen for AST_CONTROL_T38_PARAMETERS. Expected %d, got %d\n", (int) sizeof(struct ast_control_t38_parameters), (int) datalen);
 		} else {
 			const struct ast_control_t38_parameters *parameters = data;
-			interpret_t38_parameters(p, parameters->request_response, parameters);
+			interpret_t38_parameters(p, parameters);
 		}
 		break;
 	case AST_CONTROL_SRCUPDATE:
@@ -7062,7 +6931,7 @@ static struct ast_frame *sip_rtp_read(struct ast_channel *ast, struct sip_pvt *p
 	if (f && p->dsp) {
 		f = ast_dsp_process(p->owner, p->dsp, f);
 		if (f && f->frametype == AST_FRAME_DTMF) {
-			if (ast_test_flag(&p->t38.t38support, SIP_PAGE2_T38SUPPORT) && f->subclass == 'f') {
+			if (ast_test_flag(&p->flags[1], SIP_PAGE2_T38SUPPORT) && f->subclass == 'f') {
 				ast_debug(1, "Fax CNG detected on %s\n", ast->name);
 				*faxdetect = 1;
 			} else {
@@ -7087,7 +6956,7 @@ static struct ast_frame *sip_read(struct ast_channel *ast)
 
 	/* If we are NOT bridged to another channel, and we have detected fax tone we issue T38 re-invite to a peer */
 	/* If we are bridged then it is the responsibility of the SIP device to issue T38 re-invite if it detects CNG or fax preamble */
-	if (faxdetected && ast_test_flag(&p->t38.t38support, SIP_PAGE2_T38SUPPORT) && (p->t38.state == T38_DISABLED) && !(ast_bridged_channel(ast))) {
+	if (faxdetected && ast_test_flag(&p->flags[1], SIP_PAGE2_T38SUPPORT) && (p->t38.state == T38_DISABLED) && !(ast_bridged_channel(ast))) {
 		if (!ast_test_flag(&p->flags[0], SIP_GOTREFER)) {
 			if (!p->pendinginvite) {
 				ast_debug(3, "Sending reinvite on SIP (%s) for T.38 negotiation.\n", ast->name);
@@ -7261,9 +7130,7 @@ static struct sip_pvt *sip_alloc(ast_string_field callid, struct sockaddr_in *si
 	    (ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_AUTO))
 		p->noncodeccapability |= AST_RTP_DTMF;
 	if (p->udptl) {
-		ast_copy_flags(&p->t38.t38support, &p->flags[1], SIP_PAGE2_T38SUPPORT);
 		set_t38_capabilities(p);
-		p->t38.jointcapability = p->t38.capability;
 	}
 	ast_string_field_set(p, context, sip_cfg.default_context);
 	ast_string_field_set(p, parkinglot, default_parkinglot);
@@ -8050,7 +7917,6 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
 	int vportno = -1;		/*!< RTP Video port number */
 	int tportno = -1;		/*!< RTP Text port number */
 	int udptlportno = -1;
-	int peert38capability = 0;
 	char s[256];
 	int old = 0;
 
@@ -8590,6 +8456,7 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
 		int found = 0, x;
 		
 		old = 0;
+		memset(&p->t38.their_parms, 0, sizeof(p->t38.their_parms));
 		
 		/* Scan trough the a= lines for T38 attributes and set apropriate fileds */
 		iterator = req->sdp_start;
@@ -8602,110 +8469,92 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
 				ast_debug(3, "T38MaxBitRate: %d\n", x);
 				switch (x) {
 				case 14400:
-					peert38capability |= T38FAX_RATE_14400 | T38FAX_RATE_12000 | T38FAX_RATE_9600 | T38FAX_RATE_7200 | T38FAX_RATE_4800 | T38FAX_RATE_2400;
+					p->t38.their_parms.rate = AST_T38_RATE_14400;
 					break;
 				case 12000:
-					peert38capability |= T38FAX_RATE_12000 | T38FAX_RATE_9600 | T38FAX_RATE_7200 | T38FAX_RATE_4800 | T38FAX_RATE_2400;
+					p->t38.their_parms.rate = AST_T38_RATE_12000;
 					break;
 				case 9600:
-					peert38capability |= T38FAX_RATE_9600 | T38FAX_RATE_7200 | T38FAX_RATE_4800 | T38FAX_RATE_2400;
+					p->t38.their_parms.rate = AST_T38_RATE_9600;
 					break;
 				case 7200:
-					peert38capability |= T38FAX_RATE_7200 | T38FAX_RATE_4800 | T38FAX_RATE_2400;
+					p->t38.their_parms.rate = AST_T38_RATE_7200;
 					break;
 				case 4800:
-					peert38capability |= T38FAX_RATE_4800 | T38FAX_RATE_2400;
+					p->t38.their_parms.rate = AST_T38_RATE_4800;
 					break;
 				case 2400:
-					peert38capability |= T38FAX_RATE_2400;
+					p->t38.their_parms.rate = AST_T38_RATE_2400;
 					break;
 				}
 			} else if ((sscanf(a, "T38FaxVersion:%d", &x) == 1)) {
 				found = 1;
 				ast_debug(3, "FaxVersion: %d\n", x);
-				if (x == 0)
-					peert38capability |= T38FAX_VERSION_0;
-				else if (x == 1)
-					peert38capability |= T38FAX_VERSION_1;
+				p->t38.their_parms.version = x;
 			} else if ((sscanf(a, "T38FaxMaxDatagram:%d", &x) == 1) || (sscanf(a, "T38MaxDatagram:%d", &x) == 1)) {
 				found = 1;
 				ast_debug(3, "FaxMaxDatagram: %d\n", x);
 				ast_udptl_set_far_max_datagram(p->udptl, x);
-				if (!ast_udptl_get_local_max_datagram(p->udptl)) {
-					ast_udptl_set_local_max_datagram(p->udptl, x);
-				}
 			} else if ((strncmp(a, "T38FaxFillBitRemoval", 20) == 0)) {
 				found = 1;
-				if(sscanf(a, "T38FaxFillBitRemoval:%d", &x) == 1) {
-				    ast_debug(3, "FillBitRemoval: %d\n", x);
-				    if(x == 1)
-					peert38capability |= T38FAX_FILL_BIT_REMOVAL;
+				if (sscanf(a, "T38FaxFillBitRemoval:%d", &x) == 1) {
+					ast_debug(3, "FillBitRemoval: %d\n", x);
+					if (x == 1) {
+						p->t38.their_parms.fill_bit_removal = TRUE;
+					}
 				} else {
-				    ast_debug(3, "FillBitRemoval\n");
-				    peert38capability |= T38FAX_FILL_BIT_REMOVAL;
+					ast_debug(3, "FillBitRemoval\n");
+					p->t38.their_parms.fill_bit_removal = TRUE;
 				}
 			} else if ((strncmp(a, "T38FaxTranscodingMMR", 20) == 0)) {
 				found = 1;
-				if(sscanf(a, "T38FaxTranscodingMMR:%d", &x) == 1) {
-				    ast_debug(3, "Transcoding MMR: %d\n", x);
-				    if(x == 1)
-					peert38capability |= T38FAX_TRANSCODING_MMR;
+				if (sscanf(a, "T38FaxTranscodingMMR:%d", &x) == 1) {
+					ast_debug(3, "Transcoding MMR: %d\n", x);
+					if (x == 1) {
+						p->t38.their_parms.transcoding_mmr = TRUE;
+					}
 				} else {
-				    ast_debug(3, "Transcoding MMR\n");
-				    peert38capability |= T38FAX_TRANSCODING_MMR;
+					ast_debug(3, "Transcoding MMR\n");
+					p->t38.their_parms.transcoding_mmr = TRUE;
 				}
 			} else if ((strncmp(a, "T38FaxTranscodingJBIG", 21) == 0)) {
 				found = 1;
-				if(sscanf(a, "T38FaxTranscodingJBIG:%d", &x) == 1) {
-				    ast_debug(3, "Transcoding JBIG: %d\n", x);
-				    if(x == 1)
-					peert38capability |= T38FAX_TRANSCODING_JBIG;
+				if (sscanf(a, "T38FaxTranscodingJBIG:%d", &x) == 1) {
+					ast_debug(3, "Transcoding JBIG: %d\n", x);
+					if (x == 1) {
+						p->t38.their_parms.transcoding_jbig = TRUE;
+					}
 				} else {
-				    ast_debug(3, "Transcoding JBIG\n");
-				    peert38capability |= T38FAX_TRANSCODING_JBIG;
+					ast_debug(3, "Transcoding JBIG\n");
+					p->t38.their_parms.transcoding_jbig = TRUE;
 				}
 			} else if ((sscanf(a, "T38FaxRateManagement:%255s", s) == 1)) {
 				found = 1;
 				ast_debug(3, "RateManagement: %s\n", s);
 				if (!strcasecmp(s, "localTCF"))
-					peert38capability |= T38FAX_RATE_MANAGEMENT_LOCAL_TCF;
+					p->t38.their_parms.rate_management = AST_T38_RATE_MANAGEMENT_LOCAL_TCF;
 				else if (!strcasecmp(s, "transferredTCF"))
-					peert38capability |= T38FAX_RATE_MANAGEMENT_TRANSFERRED_TCF;
+					p->t38.their_parms.rate_management = AST_T38_RATE_MANAGEMENT_TRANSFERRED_TCF;
 			} else if ((sscanf(a, "T38FaxUdpEC:%255s", s) == 1)) {
 				found = 1;
 				ast_debug(3, "UDP EC: %s\n", s);
 				if (!strcasecmp(s, "t38UDPRedundancy")) {
-					peert38capability |= T38FAX_UDP_EC_REDUNDANCY;
 					ast_udptl_set_error_correction_scheme(p->udptl, UDPTL_ERROR_CORRECTION_REDUNDANCY);
 				} else if (!strcasecmp(s, "t38UDPFEC")) {
-					peert38capability |= T38FAX_UDP_EC_FEC;
 					ast_udptl_set_error_correction_scheme(p->udptl, UDPTL_ERROR_CORRECTION_FEC);
 				} else {
-					peert38capability |= T38FAX_UDP_EC_NONE;
 					ast_udptl_set_error_correction_scheme(p->udptl, UDPTL_ERROR_CORRECTION_NONE);
 				}
 			}
 		}
-		if (found) { /* Some cisco equipment returns nothing beside c= and m= lines in 200 OK T38 SDP */
-			p->t38.peercapability = peert38capability;
-			p->t38.jointcapability = (peert38capability & 255); /* Put everything beside supported speeds settings */
-			peert38capability &= (T38FAX_RATE_14400 | T38FAX_RATE_12000 | T38FAX_RATE_9600 | T38FAX_RATE_7200 | T38FAX_RATE_4800 | T38FAX_RATE_2400);
-			p->t38.jointcapability |= (peert38capability & p->t38.capability); /* Put the lower of our's and peer's speed */
-		}
-		if (debug)
-			ast_debug(1, "Our T38 capability = (%d), peer T38 capability (%d), joint T38 capability (%d)\n",
-				p->t38.capability,
-				p->t38.peercapability,
-				p->t38.jointcapability);
 
 		/* Remote party offers T38, we need to update state */
-		if (t38action == SDP_T38_ACCEPT) {
-			if (p->t38.state == T38_LOCAL_REINVITE)
-				change_t38_state(p, T38_ENABLED);
-		} else if (t38action == SDP_T38_INITIATE) {
-			if (p->owner && p->lastinvite) {
-				change_t38_state(p, T38_PEER_REINVITE); /* T38 Offered in re-invite from remote party */
-			}
+		if ((t38action == SDP_T38_ACCEPT) &&
+		    (p->t38.state == T38_LOCAL_REINVITE)) {
+			change_t38_state(p, T38_ENABLED);
+		} else if ((t38action == SDP_T38_INITIATE) &&
+			   p->owner && p->lastinvite) {
+			change_t38_state(p, T38_PEER_REINVITE); /* T38 Offered in re-invite from remote party */
 		}
 	} else {
 		change_t38_state(p, T38_DISABLED);
@@ -8744,7 +8593,7 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
 	}
 	if (!newjointcapability) {
 		/* If T.38 was not negotiated either, totally bail out... */
-		if (!p->t38.jointcapability || !udptlportno) {
+		if ((p->t38.state == T38_DISABLED) || !udptlportno) {
 			ast_log(LOG_NOTICE, "No compatible codecs, not accepting this offer!\n");
 			/* Do NOT Change current setting */
 			return -1;
@@ -9885,30 +9734,22 @@ static void add_tcodec_to_sdp(const struct sip_pvt *p, int codec,
 
 
 /*! \brief Get Max T.38 Transmission rate from T38 capabilities */
-static int t38_get_rate(int t38cap)
+static unsigned int t38_get_rate(enum ast_control_t38_rate rate)
 {
-	int maxrate = (t38cap & (T38FAX_RATE_14400 | T38FAX_RATE_12000 | T38FAX_RATE_9600 | T38FAX_RATE_7200 | T38FAX_RATE_4800 | T38FAX_RATE_2400));
-	
-	if (maxrate & T38FAX_RATE_14400) {
-		ast_debug(2, "T38MaxBitRate 14400 found\n");
-		return 14400;
-	} else if (maxrate & T38FAX_RATE_12000) {
-		ast_debug(2, "T38MaxBitRate 12000 found\n");
-		return 12000;
-	} else if (maxrate & T38FAX_RATE_9600) {
-		ast_debug(2, "T38MaxBitRate 9600 found\n");
-		return 9600;
-	} else if (maxrate & T38FAX_RATE_7200) {
-		ast_debug(2, "T38MaxBitRate 7200 found\n");
-		return 7200;
-	} else if (maxrate & T38FAX_RATE_4800) {
-		ast_debug(2, "T38MaxBitRate 4800 found\n");
-		return 4800;
-	} else if (maxrate & T38FAX_RATE_2400) {
-		ast_debug(2, "T38MaxBitRate 2400 found\n");
+	switch (rate) {
+	case AST_T38_RATE_2400:
 		return 2400;
-	} else {
-		ast_debug(2, "Strange, T38MaxBitRate NOT found in peers T38 SDP.\n");
+	case AST_T38_RATE_4800:
+		return 4800;
+	case AST_T38_RATE_7200:
+		return 7200;
+	case AST_T38_RATE_9600:
+		return 9600;
+	case AST_T38_RATE_12000:
+		return 12000;
+	case AST_T38_RATE_14400:
+		return 14400;
+	default:
 		return 0;
 	}
 }
@@ -10224,35 +10065,38 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int
 		/* We break with the "recommendation" and send our IP, in order that our
 		   peer doesn't have to ast_gethostbyname() us */
 
-		if (debug) {
-			ast_debug(1, "Our T38 capability (%d), peer T38 capability (%d), joint capability (%d)\n",
-				  p->t38.capability,
-				  p->t38.peercapability,
-				  p->t38.jointcapability);
-		}
-
 		ast_str_append(&m_modem, 0, "m=image %d udptl t38", ntohs(udptldest.sin_port));
 
-		if ((p->t38.jointcapability & T38FAX_VERSION) == T38FAX_VERSION_0)
-			ast_str_append(&a_modem, 0, "a=T38FaxVersion:0\r\n");
-		if ((p->t38.jointcapability & T38FAX_VERSION) == T38FAX_VERSION_1)
-			ast_str_append(&a_modem, 0, "a=T38FaxVersion:1\r\n");
-		if ((x = t38_get_rate(p->t38.jointcapability)))
-			ast_str_append(&a_modem, 0, "a=T38MaxBitRate:%d\r\n", x);
-		if ((p->t38.jointcapability & T38FAX_FILL_BIT_REMOVAL) == T38FAX_FILL_BIT_REMOVAL)
+		ast_str_append(&a_modem, 0, "a=T38Faxversion:%d\r\n", p->t38.our_parms.version);
+		ast_str_append(&a_modem, 0, "a=T38MaxBitRate:%d\r\n", t38_get_rate(p->t38.our_parms.rate));
+		if (p->t38.our_parms.fill_bit_removal) {
 			ast_str_append(&a_modem, 0, "a=T38FaxFillBitRemoval\r\n");
-		if ((p->t38.jointcapability & T38FAX_TRANSCODING_MMR) == T38FAX_TRANSCODING_MMR)
+		}
+		if (p->t38.our_parms.transcoding_mmr) {
 			ast_str_append(&a_modem, 0, "a=T38FaxTranscodingMMR\r\n");
-		if ((p->t38.jointcapability & T38FAX_TRANSCODING_JBIG) == T38FAX_TRANSCODING_JBIG)
+		}
+		if (p->t38.our_parms.transcoding_jbig) {
 			ast_str_append(&a_modem, 0, "a=T38FaxTranscodingJBIG\r\n");
-		ast_str_append(&a_modem, 0, "a=T38FaxRateManagement:%s\r\n", (p->t38.jointcapability & T38FAX_RATE_MANAGEMENT_LOCAL_TCF) ? "localTCF" : "transferredTCF");
-		x = ast_udptl_get_local_max_datagram(p->udptl);
-		ast_str_append(&a_modem, 0, "a=T38FaxMaxBuffer:%d\r\n", x);
-		ast_str_append(&a_modem, 0, "a=T38FaxMaxDatagram:%d\r\n", x);
-		if (p->t38.jointcapability & T38FAX_UDP_EC_REDUNDANCY)
-			ast_str_append(&a_modem, 0, "a=T38FaxUdpEC:t38UDPRedundancy\r\n");
-		else if (p->t38.jointcapability & T38FAX_UDP_EC_FEC)
+		}
+		switch (p->t38.our_parms.rate_management) {
+		case AST_T38_RATE_MANAGEMENT_TRANSFERRED_TCF:
+			ast_str_append(&a_modem, 0, "a=T38FaxRateManagement:transferredTCF\r\n");
+			break;
+		case AST_T38_RATE_MANAGEMENT_LOCAL_TCF:
+			ast_str_append(&a_modem, 0, "a=T38FaxRateManagement:localTCF\r\n");
+			break;
+		}
+		ast_str_append(&a_modem, 0, "a=T38FaxMaxDatagram:%d\r\n", ast_udptl_get_local_max_datagram(p->udptl));
+		switch (ast_test_flag(&p->flags[1],  SIP_PAGE2_T38SUPPORT)) {
+		case SIP_PAGE2_T38SUPPORT_UDPTL:
+			break;
+		case SIP_PAGE2_T38SUPPORT_UDPTL_FEC:
 			ast_str_append(&a_modem, 0, "a=T38FaxUdpEC:t38UDPFEC\r\n");
+			break;
+		case SIP_PAGE2_T38SUPPORT_UDPTL_REDUNDANCY:
+			ast_str_append(&a_modem, 0, "a=T38FaxUdpEC:t38UDPRedundancy\r\n");
+			break;
+		}
 	}
 
 	if (needaudio)
@@ -10335,7 +10179,6 @@ static int transmit_response_with_t38_sdp(struct sip_pvt *p, char *msg, struct s
 	}
 	respprep(&resp, p, msg, req);
 	if (p->udptl) {
-		ast_udptl_offered_from_local(p->udptl, 0);
 		add_sdp(&resp, p, 0, 0, 1);
 	} else 
 		ast_log(LOG_ERROR, "Can't add SDP to response, since we have no UDPTL session allocated. Call-ID %s\n", p->callid);
@@ -10862,7 +10705,6 @@ static int transmit_invite(struct sip_pvt *p, int sipmethod, int sdp, int init)
 	if (sdp) {
 		memset(p->offered_media, 0, sizeof(p->offered_media));
 		if (p->udptl && p->t38.state == T38_LOCAL_REINVITE) {
-			ast_udptl_offered_from_local(p->udptl, 1);
 			ast_debug(1, "T38 is in state %d on channel %s\n", p->t38.state, p->owner ? p->owner->name : "<none>");
 			add_sdp(&req, p, FALSE, FALSE, TRUE);
 		} else if (p->rtp) {
@@ -14132,7 +13974,6 @@ static enum check_auth_result check_peer_ok(struct sip_pvt *p, char *of,
 
 	if (ast_test_flag(&p->flags[1], SIP_PAGE2_T38SUPPORT) && p->udptl) {
 		set_t38_capabilities(p);
-		p->t38.jointcapability = p->t38.capability;
 	}
 
 	/* Copy SIP extensions profile to peer */
@@ -14231,8 +14072,6 @@ static enum check_auth_result check_peer_ok(struct sip_pvt *p, char *of,
 		else
 			p->noncodeccapability &= ~AST_RTP_DTMF;
 		p->jointnoncodeccapability = p->noncodeccapability;
-		if (p->t38.peercapability)
-			p->t38.jointcapability &= p->t38.peercapability;
 		if (!dialog_initialize_rtp(p)) {
 			if (p->rtp) {
 				ast_rtp_codecs_packetization_set(ast_rtp_instance_get_codecs(p->rtp), p->rtp, &peer->prefs);
@@ -20394,9 +20233,6 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int
 		/* If T38 is needed but not present, then make it magically appear */
 		if (ast_test_flag(&p->flags[1], SIP_PAGE2_T38SUPPORT) && !p->udptl && (p->udptl = ast_udptl_new_with_bindaddr(sched, io, 0, bindaddr.sin_addr))) {
 			set_t38_capabilities(p);
-			p->t38.jointcapability = p->t38.capability;
-			set_t38_capabilities(p);
-			p->t38.jointcapability = p->t38.capability;
 		}
 
 		/* We have a succesful authentication, process the SDP portion if there is one */
diff --git a/include/asterisk/frame.h b/include/asterisk/frame.h
index e64800754b9c3b2db33eb612822c838f89b61e1d..db90e1845999b967c3f4c2d2dcf8370ff5b418b2 100644
--- a/include/asterisk/frame.h
+++ b/include/asterisk/frame.h
@@ -319,7 +319,7 @@ enum ast_control_frame_type {
 	AST_CONTROL_HOLD = 16,		/*!< Indicate call is placed on hold */
 	AST_CONTROL_UNHOLD = 17,	/*!< Indicate call is left from hold */
 	AST_CONTROL_VIDUPDATE = 18,	/*!< Indicate video frame update */
-	AST_CONTROL_T38 = 19,		/*!< T38 state change request/notification */
+	_XXX_AST_CONTROL_T38 = 19,	/*!< T38 state change request/notification \deprecated This is no longer supported. Use AST_CONTROL_T38_PARAMETERS instead. */
 	AST_CONTROL_SRCUPDATE = 20,     /*!< Indicate source of media has changed */
 	AST_CONTROL_TRANSFER = 21,      /*!< Indicate status of a transfer request */
 	AST_CONTROL_CONNECTED_LINE = 22,/*!< Indicate connected line has changed */
@@ -350,14 +350,14 @@ enum ast_control_t38_rate_management {
 };
 
 struct ast_control_t38_parameters {
-	enum ast_control_t38 request_response;                /*!< Request or response of the T38 control frame */
-	unsigned int version;                                 /*!< Supported T.38 version */
-	unsigned int max_datagram;                            /*!< Maximum datagram size supported */
-	enum ast_control_t38_rate rate;                       /*!< Maximum fax rate supported */
-	enum ast_control_t38_rate_management rate_management; /*!< Rate management setting */
-	unsigned int fill_bit_removal:1;                      /*!< Set if fill bit removal should be used */
-	unsigned int transcoding_mmr:1;                       /*!< Set if MMR transcoding should be used */
-	unsigned int transcoding_jbig:1;                      /*!< Set if JBIG transcoding should be used */
+	enum ast_control_t38 request_response;			/*!< Request or response of the T38 control frame */
+	unsigned int version;					/*!< Supported T.38 version */
+	unsigned int max_ifp; 					/*!< Maximum IFP size supported */
+	enum ast_control_t38_rate rate;				/*!< Maximum fax rate supported */
+	enum ast_control_t38_rate_management rate_management;	/*!< Rate management setting */
+	unsigned int fill_bit_removal:1;			/*!< Set if fill bit removal can be used */
+	unsigned int transcoding_mmr:1;				/*!< Set if MMR transcoding can be used */
+	unsigned int transcoding_jbig:1;			/*!< Set if JBIG transcoding can be used */
 };
 
 enum ast_control_transfer {
diff --git a/include/asterisk/udptl.h b/include/asterisk/udptl.h
index 4d6b890687fe1372767180515e0ec2497edf6136..72b9af4aaab46a4b75a8bcb1410b1570c61aa861 100644
--- a/include/asterisk/udptl.h
+++ b/include/asterisk/udptl.h
@@ -33,7 +33,7 @@
 #include "asterisk/channel.h"
 
 
-enum {
+enum ast_t38_ec_modes {
     UDPTL_ERROR_CORRECTION_NONE,
     UDPTL_ERROR_CORRECTION_FEC,
     UDPTL_ERROR_CORRECTION_REDUNDANCY
@@ -60,11 +60,11 @@ struct ast_udptl *ast_udptl_new(struct sched_context *sched, struct io_context *
 
 struct ast_udptl *ast_udptl_new_with_bindaddr(struct sched_context *sched, struct io_context *io, int callbackmode, struct in_addr in);
 
-void ast_udptl_set_peer(struct ast_udptl *udptl, struct sockaddr_in *them);
+void ast_udptl_set_peer(struct ast_udptl *udptl, const struct sockaddr_in *them);
 
-void ast_udptl_get_peer(struct ast_udptl *udptl, struct sockaddr_in *them);
+void ast_udptl_get_peer(const struct ast_udptl *udptl, struct sockaddr_in *them);
 
-void ast_udptl_get_us(struct ast_udptl *udptl, struct sockaddr_in *us);
+void ast_udptl_get_us(const struct ast_udptl *udptl, struct sockaddr_in *us);
 
 void ast_udptl_destroy(struct ast_udptl *udptl);
 
@@ -78,37 +78,33 @@ int ast_udptl_write(struct ast_udptl *udptl, struct ast_frame *f);
 
 struct ast_frame *ast_udptl_read(struct ast_udptl *udptl);
 
-int ast_udptl_fd(struct ast_udptl *udptl);
+int ast_udptl_fd(const struct ast_udptl *udptl);
 
-int ast_udptl_setqos(struct ast_udptl *udptl, int tos, int cos);
+int ast_udptl_setqos(struct ast_udptl *udptl, unsigned int tos, unsigned int cos);
 
-void ast_udptl_set_m_type(struct ast_udptl* udptl, int pt);
+void ast_udptl_set_m_type(struct ast_udptl *udptl, unsigned int pt);
 
-void ast_udptl_set_udptlmap_type(struct ast_udptl* udptl, int pt,
-			 char* mimeType, char* mimeSubtype);
+void ast_udptl_set_udptlmap_type(struct ast_udptl *udptl, unsigned int pt,
+				 char *mimeType, char *mimeSubtype);
 
-int ast_udptl_lookup_code(struct ast_udptl* udptl, int isAstFormat, int code);
+int ast_udptl_get_error_correction_scheme(const struct ast_udptl *udptl);
 
-void ast_udptl_offered_from_local(struct ast_udptl* udptl, int local);
+void ast_udptl_set_error_correction_scheme(struct ast_udptl *udptl, enum ast_t38_ec_modes ec);
 
-int ast_udptl_get_error_correction_scheme(struct ast_udptl* udptl);
+void ast_udptl_set_local_max_ifp(struct ast_udptl *udptl, unsigned int max_ifp);
 
-void ast_udptl_set_error_correction_scheme(struct ast_udptl* udptl, int ec);
+unsigned int ast_udptl_get_local_max_datagram(const struct ast_udptl *udptl);
 
-int ast_udptl_get_local_max_datagram(struct ast_udptl* udptl);
+void ast_udptl_set_far_max_datagram(struct ast_udptl *udptl, unsigned int max_datagram);
 
-void ast_udptl_set_local_max_datagram(struct ast_udptl* udptl, int max_datagram);
+unsigned int ast_udptl_get_far_max_datagram(const struct ast_udptl *udptl);
 
-int ast_udptl_get_far_max_datagram(struct ast_udptl* udptl);
-
-void ast_udptl_set_far_max_datagram(struct ast_udptl* udptl, int max_datagram);
-
-void ast_udptl_get_current_formats(struct ast_udptl* udptl,
-			     int* astFormats, int* nonAstFormats);
+unsigned int ast_udptl_get_far_max_ifp(const struct ast_udptl *udptl);
 
 void ast_udptl_setnat(struct ast_udptl *udptl, int nat);
 
-int ast_udptl_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc);
+int ast_udptl_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags,
+		     struct ast_frame **fo, struct ast_channel **rc);
 
 int ast_udptl_proto_register(struct ast_udptl_protocol *proto);
 
diff --git a/main/channel.c b/main/channel.c
index dce0747d5778eb1adcd30103c0140f1f38bf76b4..1052d0fe8fde1b60181ae75a32e75b724fc98d67 100644
--- a/main/channel.c
+++ b/main/channel.c
@@ -3488,11 +3488,11 @@ static int attribute_const is_visible_indication(enum ast_control_frame_type con
 	case AST_CONTROL_TAKEOFFHOOK:
 	case AST_CONTROL_ANSWER:
 	case AST_CONTROL_HANGUP:
-	case AST_CONTROL_T38:
 	case AST_CONTROL_CONNECTED_LINE:
 	case AST_CONTROL_REDIRECTING:
 	case AST_CONTROL_TRANSFER:
 	case AST_CONTROL_T38_PARAMETERS:
+	case _XXX_AST_CONTROL_T38:
 		break;
 
 	case AST_CONTROL_CONGESTION:
@@ -3585,7 +3585,9 @@ int ast_indicate_data(struct ast_channel *chan, int _condition,
 
 	/* Handle conditions that we have tones for. */
 	switch (condition) {
-	case AST_CONTROL_T38:
+	case _XXX_AST_CONTROL_T38:
+		/* deprecated T.38 control frame */
+		return -1;
 	case AST_CONTROL_T38_PARAMETERS:
 		/* there is no way to provide 'default' behavior for these
 		 * control frames, so we need to return failure, but there
@@ -5503,7 +5505,6 @@ static enum ast_bridge_result ast_generic_bridge(struct ast_channel *c0, struct
 			case AST_CONTROL_HOLD:
 			case AST_CONTROL_UNHOLD:
 			case AST_CONTROL_VIDUPDATE:
-			case AST_CONTROL_T38:
 			case AST_CONTROL_SRCUPDATE:
 				ast_indicate_data(other, f->subclass, f->data.ptr, f->datalen);
 				if (jb_in_use) {
diff --git a/main/frame.c b/main/frame.c
index 09c11dbdafc25fc07f726c04c536029c72380728..fa443407c63713ba0cd37dd88e7bbd67e37d2c48 100644
--- a/main/frame.c
+++ b/main/frame.c
@@ -839,24 +839,6 @@ void ast_frame_dump(const char *name, struct ast_frame *f, char *prefix)
 		case AST_CONTROL_UNHOLD:
 			strcpy(subclass, "Unhold");
 			break;
-		case AST_CONTROL_T38:
-			if (f->datalen != sizeof(enum ast_control_t38)) {
-				message = "Invalid";
-			} else {
-				enum ast_control_t38 state = *((enum ast_control_t38 *) f->data.ptr);
-				if (state == AST_T38_REQUEST_NEGOTIATE)
-					message = "Negotiation Requested";
-				else if (state == AST_T38_REQUEST_TERMINATE)
-					message = "Negotiation Request Terminated";
-				else if (state == AST_T38_NEGOTIATED)
-					message = "Negotiated";
-				else if (state == AST_T38_TERMINATED)
-					message = "Terminated";
-				else if (state == AST_T38_REFUSED)
-					message = "Refused";
-			}
-			snprintf(subclass, sizeof(subclass), "T38/%s", message);
-			break;
 		case AST_CONTROL_T38_PARAMETERS:
 			if (f->datalen != sizeof(struct ast_control_t38_parameters *)) {
 				message = "Invalid";
diff --git a/main/rtp_engine.c b/main/rtp_engine.c
index 138b7c03cf5b6b1b1d9d27646738106abe08e8d5..573502811c58b81a7e817ddb19f5889d35ab427a 100644
--- a/main/rtp_engine.c
+++ b/main/rtp_engine.c
@@ -853,7 +853,6 @@ static enum ast_bridge_result local_bridge_loop(struct ast_channel *c0, struct a
 			if ((fr->subclass == AST_CONTROL_HOLD) ||
 			    (fr->subclass == AST_CONTROL_UNHOLD) ||
 			    (fr->subclass == AST_CONTROL_VIDUPDATE) ||
-			    (fr->subclass == AST_CONTROL_T38) ||
 			    (fr->subclass == AST_CONTROL_SRCUPDATE) ||
 			    (fr->subclass == AST_CONTROL_T38_PARAMETERS)) {
 				/* If we are going on hold, then break callback mode and P2P bridging */
@@ -1073,7 +1072,6 @@ static enum ast_bridge_result remote_bridge_loop(struct ast_channel *c0, struct
 			if ((fr->subclass == AST_CONTROL_HOLD) ||
 			    (fr->subclass == AST_CONTROL_UNHOLD) ||
 			    (fr->subclass == AST_CONTROL_VIDUPDATE) ||
-			    (fr->subclass == AST_CONTROL_T38) ||
 			    (fr->subclass == AST_CONTROL_SRCUPDATE) ||
 			    (fr->subclass == AST_CONTROL_T38_PARAMETERS)) {
 				if (fr->subclass == AST_CONTROL_HOLD) {
diff --git a/main/udptl.c b/main/udptl.c
index 7f7a2b76aa9fc638df7bf92792ef6bf06dfdf252..86a198202aa1a7bca49c546da8492fd114f9d451 100644
--- a/main/udptl.c
+++ b/main/udptl.c
@@ -81,7 +81,7 @@ static struct sockaddr_in udptldebugaddr;   /*!< Debug packets to/from this host
 #ifdef SO_NO_CHECK
 static int nochecksums;
 #endif
-static int udptlfectype;
+static enum ast_t38_ec_modes udptlfectype;
 static int udptlfecentries;
 static int udptlfecspan;
 static int udptlmaxdatagram;
@@ -100,10 +100,10 @@ typedef struct {
 typedef struct {
 	int buf_len;
 	uint8_t buf[LOCAL_FAX_MAX_DATAGRAM];
-	int fec_len[MAX_FEC_ENTRIES];
+	unsigned int fec_len[MAX_FEC_ENTRIES];
 	uint8_t fec[MAX_FEC_ENTRIES][LOCAL_FAX_MAX_DATAGRAM];
-	int fec_span;
-	int fec_entries;
+	unsigned int fec_span;
+	unsigned int fec_entries;
 } udptl_fec_rx_buffer_t;
 
 /*! \brief Structure for an UDPTL session */
@@ -122,35 +122,51 @@ struct ast_udptl {
 	struct io_context *io;
 	void *data;
 	ast_udptl_callback callback;
-	int udptl_offered_from_local;
 
 	/*! This option indicates the error correction scheme used in transmitted UDPTL
-	    packets. */
-	int error_correction_scheme;
+	 *    packets and expected in received UDPTL packets.
+	 */
+	enum ast_t38_ec_modes error_correction_scheme;
 
 	/*! This option indicates the number of error correction entries transmitted in
-	    UDPTL packets. */
-	int error_correction_entries;
+	 *  UDPTL packets and expected in received UDPTL packets.
+	 */
+	unsigned int error_correction_entries;
 
 	/*! This option indicates the span of the error correction entries in transmitted
-	    UDPTL packets (FEC only). */
-	int error_correction_span;
-
-	/*! This option indicates the maximum size of a UDPTL packet that can be accepted by
-	    the remote device. */
-	int far_max_datagram_size;
-
-	/*! This option indicates the maximum size of a UDPTL packet that we are prepared to
-	    accept. */
-	int local_max_datagram_size;
+	 *  UDPTL packets (FEC only).
+	 */
+	unsigned int error_correction_span;
+
+	/*! The maximum size UDPTL packet that can be accepted by
+	 *  the remote device.
+	 */
+	unsigned int far_max_datagram;
+
+	/*! The maximum size UDPTL packet that we are prepared to
+	 *  accept.
+	 */
+	unsigned int local_max_datagram;
+
+	/*! The maximum IFP that can be submitted for sending
+	 * to the remote device. Calculated from far_max_datagram,
+	 * error_correction_scheme and error_correction_entries.
+	 */
+	unsigned int far_max_ifp;
+
+	/*! The maximum IFP that the local endpoint is prepared
+	 * to accept. Along with error_correction_scheme and
+	 * error_correction_entries, used to calculate local_max_datagram.
+	 */
+	unsigned int local_max_ifp;
 
 	int verbose;
 
 	struct sockaddr_in far;
 
-	int tx_seq_no;
-	int rx_seq_no;
-	int rx_expected_seq_no;
+	unsigned int tx_seq_no;
+	unsigned int rx_seq_no;
+	unsigned int rx_expected_seq_no;
 
 	udptl_fec_tx_buffer_t tx[UDPTL_BUF_MASK + 1];
 	udptl_fec_rx_buffer_t rx[UDPTL_BUF_MASK + 1];
@@ -158,23 +174,20 @@ struct ast_udptl {
 
 static AST_RWLIST_HEAD_STATIC(protos, ast_udptl_protocol);
 
-static int udptl_rx_packet(struct ast_udptl *s, uint8_t *buf, int len);
-static int udptl_build_packet(struct ast_udptl *s, uint8_t *buf, int buflen, uint8_t *ifp, int ifp_len);
-
-static inline int udptl_debug_test_addr(struct sockaddr_in *addr)
+static inline int udptl_debug_test_addr(const struct sockaddr_in *addr)
 {
 	if (udptldebug == 0)
 		return 0;
 	if (udptldebugaddr.sin_addr.s_addr) {
-		if (((ntohs(udptldebugaddr.sin_port) != 0)
-			&& (udptldebugaddr.sin_port != addr->sin_port))
-			|| (udptldebugaddr.sin_addr.s_addr != addr->sin_addr.s_addr))
+		if (((ntohs(udptldebugaddr.sin_port) != 0) &&
+		     (udptldebugaddr.sin_port != addr->sin_port)) ||
+		    (udptldebugaddr.sin_addr.s_addr != addr->sin_addr.s_addr))
 			return 0;
 	}
 	return 1;
 }
 
-static int decode_length(uint8_t *buf, int limit, int *len, int *pvalue)
+static int decode_length(uint8_t *buf, unsigned int limit, unsigned int *len, unsigned int *pvalue)
 {
 	if (*len >= limit)
 		return -1;
@@ -199,15 +212,16 @@ static int decode_length(uint8_t *buf, int limit, int *len, int *pvalue)
 }
 /*- End of function --------------------------------------------------------*/
 
-static int decode_open_type(uint8_t *buf, int limit, int *len, const uint8_t **p_object, int *p_num_octets)
+static int decode_open_type(uint8_t *buf, unsigned int limit, unsigned int *len, const uint8_t **p_object, unsigned int *p_num_octets)
 {
-	int octet_cnt;
-	int octet_idx;
-	int length;
-	int i;
+	unsigned int octet_cnt;
+	unsigned int octet_idx;
+	unsigned int length;
+	unsigned int i;
 	const uint8_t **pbuf;
 
 	for (octet_idx = 0, *p_num_octets = 0; ; octet_idx += octet_cnt) {
+		octet_cnt = 0;
 		if ((length = decode_length(buf, limit, len, &octet_cnt)) < 0)
 			return -1;
 		if (octet_cnt > 0) {
@@ -229,9 +243,9 @@ static int decode_open_type(uint8_t *buf, int limit, int *len, const uint8_t **p
 }
 /*- End of function --------------------------------------------------------*/
 
-static int encode_length(uint8_t *buf, int *len, int value)
+static unsigned int encode_length(uint8_t *buf, unsigned int *len, unsigned int value)
 {
-	int multiplier;
+	unsigned int multiplier;
 
 	if (value < 0x80) {
 		/* 1 octet */
@@ -257,10 +271,10 @@ static int encode_length(uint8_t *buf, int *len, int value)
 }
 /*- End of function --------------------------------------------------------*/
 
-static int encode_open_type(uint8_t *buf, int buflen, int *len, const uint8_t *data, int num_octets)
+static int encode_open_type(uint8_t *buf, unsigned int buflen, unsigned int *len, const uint8_t *data, unsigned int num_octets)
 {
-	int enclen;
-	int octet_idx;
+	unsigned int enclen;
+	unsigned int octet_idx;
 	uint8_t zero_byte;
 
 	/* If open type is of zero length, add a single zero byte (10.1) */
@@ -289,7 +303,7 @@ static int encode_open_type(uint8_t *buf, int buflen, int *len, const uint8_t *d
 }
 /*- End of function --------------------------------------------------------*/
 
-static int udptl_rx_packet(struct ast_udptl *s, uint8_t *buf, int len)
+static int udptl_rx_packet(struct ast_udptl *s, uint8_t *buf, unsigned int len)
 {
 	int stat1;
 	int stat2;
@@ -301,16 +315,16 @@ static int udptl_rx_packet(struct ast_udptl *s, uint8_t *buf, int len)
 	int x;
 	int limit;
 	int which;
-	int ptr;
-	int count;
+	unsigned int ptr;
+	unsigned int count;
 	int total_count;
 	int seq_no;
 	const uint8_t *ifp;
 	const uint8_t *data;
-	int ifp_len;
+	unsigned int ifp_len;
 	int repaired[16];
 	const uint8_t *bufs[16];
-	int lengths[16];
+	unsigned int lengths[16];
 	int span;
 	int entries;
 	int ifp_no;
@@ -497,7 +511,7 @@ static int udptl_rx_packet(struct ast_udptl *s, uint8_t *buf, int len)
 }
 /*- End of function --------------------------------------------------------*/
 
-static int udptl_build_packet(struct ast_udptl *s, uint8_t *buf, int buflen, uint8_t *ifp, int ifp_len)
+static int udptl_build_packet(struct ast_udptl *s, uint8_t *buf, unsigned int buflen, uint8_t *ifp, unsigned int ifp_len)
 {
 	uint8_t fec[LOCAL_FAX_MAX_DATAGRAM * 2];
 	int i;
@@ -507,7 +521,7 @@ static int udptl_build_packet(struct ast_udptl *s, uint8_t *buf, int buflen, uin
 	int entries;
 	int span;
 	int m;
-	int len;
+	unsigned int len;
 	int limit;
 	int high_tide;
 
@@ -612,7 +626,7 @@ static int udptl_build_packet(struct ast_udptl *s, uint8_t *buf, int buflen, uin
 	return len;
 }
 
-int ast_udptl_fd(struct ast_udptl *udptl)
+int ast_udptl_fd(const struct ast_udptl *udptl)
 {
 	return udptl->fd;
 }
@@ -695,15 +709,67 @@ struct ast_frame *ast_udptl_read(struct ast_udptl *udptl)
 	return &udptl->f[0];
 }
 
-void ast_udptl_offered_from_local(struct ast_udptl* udptl, int local)
+static void calculate_local_max_datagram(struct ast_udptl *udptl)
 {
-	if (udptl)
-		udptl->udptl_offered_from_local = local;
-	else
-		ast_log(LOG_WARNING, "udptl structure is null\n");
+	unsigned int new_max = 200;
+
+	/* calculate the amount of space required to receive an IFP
+	 * using the current error correction mode, and ensure that our
+	 * local max datagram size is at least that big
+	 */
+	switch (udptl->error_correction_scheme) {
+	case UDPTL_ERROR_CORRECTION_NONE:
+		/* only need room for sequence number and length indicators */
+		new_max = 6 + udptl->local_max_ifp;
+		break;
+	case UDPTL_ERROR_CORRECTION_REDUNDANCY:
+		/* need room for sequence number, length indicators and the
+		 * configured number of redundant packets
+		 */
+		new_max = 6 + udptl->local_max_ifp + 2 + (udptl->error_correction_entries * udptl->local_max_ifp);
+		break;
+	case UDPTL_ERROR_CORRECTION_FEC:
+		/* need room for sequence number, length indicators and a
+		 * a single IFP of the maximum size expected
+		 */
+		new_max = 6 + udptl->local_max_ifp + 4 + udptl->local_max_ifp;
+		break;
+	}
+	/* add 25% of extra space for insurance, but no larger than LOCAL_FAX_MAX_DATAGRAM */
+	udptl->local_max_datagram = MIN(new_max * 1.25, LOCAL_FAX_MAX_DATAGRAM);
+}
+
+static void calculate_far_max_ifp(struct ast_udptl *udptl)
+{
+	unsigned new_max = 40;
+
+	/* calculate the maximum IFP the local endpoint should
+	 * generate based on the far end's maximum datagram size
+	 * and the current error correction mode
+	 */
+	switch (udptl->error_correction_scheme) {
+	case UDPTL_ERROR_CORRECTION_NONE:
+		/* only need room for sequence number and length indicators */
+		new_max = udptl->far_max_datagram - 6;
+		break;
+	case UDPTL_ERROR_CORRECTION_REDUNDANCY:
+		/* need room for sequence number, length indicators and the
+		 * configured number of redundant packets
+		 */
+		new_max = (udptl->far_max_datagram - 8) / (udptl->error_correction_entries + 1);
+		break;
+	case UDPTL_ERROR_CORRECTION_FEC:
+		/* need room for sequence number, length indicators and a
+		 * a single IFP of the maximum size expected
+		 */
+		new_max = (udptl->far_max_datagram - 10) / 2;
+		break;
+	}
+	/* subtract 25% of space for insurance */
+	udptl->far_max_ifp = new_max * 0.75;
 }
 
-int ast_udptl_get_error_correction_scheme(struct ast_udptl* udptl)
+int ast_udptl_get_error_correction_scheme(const struct ast_udptl *udptl)
 {
 	if (udptl)
 		return udptl->error_correction_scheme;
@@ -713,60 +779,75 @@ int ast_udptl_get_error_correction_scheme(struct ast_udptl* udptl)
 	}
 }
 
-void ast_udptl_set_error_correction_scheme(struct ast_udptl* udptl, int ec)
+void ast_udptl_set_error_correction_scheme(struct ast_udptl *udptl, enum ast_t38_ec_modes ec)
 {
 	if (udptl) {
+		udptl->error_correction_scheme = ec;
 		switch (ec) {
 		case UDPTL_ERROR_CORRECTION_FEC:
 			udptl->error_correction_scheme = UDPTL_ERROR_CORRECTION_FEC;
+			if (udptl->error_correction_entries == 0) {
+				udptl->error_correction_entries = 3;
+			}
+			if (udptl->error_correction_span == 0) {
+				udptl->error_correction_span = 3;
+			}
 			break;
 		case UDPTL_ERROR_CORRECTION_REDUNDANCY:
 			udptl->error_correction_scheme = UDPTL_ERROR_CORRECTION_REDUNDANCY;
-			break;
-		case UDPTL_ERROR_CORRECTION_NONE:
-			udptl->error_correction_scheme = UDPTL_ERROR_CORRECTION_NONE;
+			if (udptl->error_correction_entries == 0) {
+				udptl->error_correction_entries = 3;
+			}
 			break;
 		default:
-			ast_log(LOG_WARNING, "error correction parameter invalid\n");
+			/* nothing to do */
+			break;
 		};
+		calculate_local_max_datagram(udptl);
+		calculate_far_max_ifp(udptl);
 	} else
 		ast_log(LOG_WARNING, "udptl structure is null\n");
 }
 
-int ast_udptl_get_local_max_datagram(struct ast_udptl* udptl)
+unsigned int ast_udptl_get_local_max_datagram(const struct ast_udptl *udptl)
 {
 	if (udptl)
-		return udptl->local_max_datagram_size;
+		return udptl->local_max_datagram;
 	else {
 		ast_log(LOG_WARNING, "udptl structure is null\n");
-		return -1;
+		return 0;
 	}
 }
 
-int ast_udptl_get_far_max_datagram(struct ast_udptl* udptl)
+unsigned int ast_udptl_get_far_max_datagram(const struct ast_udptl *udptl)
 {
 	if (udptl)
-		return udptl->far_max_datagram_size;
+		return udptl->far_max_datagram;
 	else {
 		ast_log(LOG_WARNING, "udptl structure is null\n");
-		return -1;
+		return 0;
 	}
 }
 
-void ast_udptl_set_local_max_datagram(struct ast_udptl* udptl, int max_datagram)
+void ast_udptl_set_far_max_datagram(struct ast_udptl *udptl, unsigned int max_datagram)
 {
-	if (udptl)
-		udptl->local_max_datagram_size = max_datagram;
-	else
+	if (udptl) {
+		udptl->far_max_datagram = max_datagram;
+		calculate_far_max_ifp(udptl);
+	} else {
 		ast_log(LOG_WARNING, "udptl structure is null\n");
+	}
 }
 
-void ast_udptl_set_far_max_datagram(struct ast_udptl* udptl, int max_datagram)
+void ast_udptl_set_local_max_ifp(struct ast_udptl *udptl, unsigned int max_ifp)
 {
-	if (udptl)
-		udptl->far_max_datagram_size = max_datagram;
-	else
-		ast_log(LOG_WARNING, "udptl structure is null\n");
+	udptl->local_max_ifp = max_ifp;
+	calculate_local_max_datagram(udptl);
+}
+
+unsigned int ast_udptl_get_far_max_ifp(const struct ast_udptl *udptl)
+{
+	return udptl->far_max_ifp;
 }
 
 struct ast_udptl *ast_udptl_new_with_bindaddr(struct sched_context *sched, struct io_context *io, int callbackmode, struct in_addr addr)
@@ -780,20 +861,13 @@ struct ast_udptl *ast_udptl_new_with_bindaddr(struct sched_context *sched, struc
 	if (!(udptl = ast_calloc(1, sizeof(*udptl))))
 		return NULL;
 
-	if (udptlfectype == 2)
-		udptl->error_correction_scheme = UDPTL_ERROR_CORRECTION_FEC;
-	else if (udptlfectype == 1)
-		udptl->error_correction_scheme = UDPTL_ERROR_CORRECTION_REDUNDANCY;
-	else
-		udptl->error_correction_scheme = UDPTL_ERROR_CORRECTION_NONE;
+	udptl->error_correction_scheme = udptlfectype;
 	udptl->error_correction_span = udptlfecspan;
 	udptl->error_correction_entries = udptlfecentries;
 	
-	udptl->far_max_datagram_size = udptlmaxdatagram;
-	udptl->local_max_datagram_size = udptlmaxdatagram;
+	udptl->far_max_datagram = udptlmaxdatagram;
+	udptl->local_max_datagram = udptlmaxdatagram;
 
-	memset(&udptl->rx, 0, sizeof(udptl->rx));
-	memset(&udptl->tx, 0, sizeof(udptl->tx));
 	for (i = 0; i <= UDPTL_BUF_MASK; i++) {
 		udptl->rx[i].buf_len = -1;
 		udptl->tx[i].buf_len = -1;
@@ -852,18 +926,18 @@ struct ast_udptl *ast_udptl_new(struct sched_context *sched, struct io_context *
 	return ast_udptl_new_with_bindaddr(sched, io, callbackmode, ia);
 }
 
-int ast_udptl_setqos(struct ast_udptl *udptl, int tos, int cos)
+int ast_udptl_setqos(struct ast_udptl *udptl, unsigned int tos, unsigned int cos)
 {
 	return ast_netsock_set_qos(udptl->fd, tos, cos, "UDPTL");
 }
 
-void ast_udptl_set_peer(struct ast_udptl *udptl, struct sockaddr_in *them)
+void ast_udptl_set_peer(struct ast_udptl *udptl, const struct sockaddr_in *them)
 {
 	udptl->them.sin_port = them->sin_port;
 	udptl->them.sin_addr = them->sin_addr;
 }
 
-void ast_udptl_get_peer(struct ast_udptl *udptl, struct sockaddr_in *them)
+void ast_udptl_get_peer(const struct ast_udptl *udptl, struct sockaddr_in *them)
 {
 	memset(them, 0, sizeof(*them));
 	them->sin_family = AF_INET;
@@ -871,7 +945,7 @@ void ast_udptl_get_peer(struct ast_udptl *udptl, struct sockaddr_in *them)
 	them->sin_addr = udptl->them.sin_addr;
 }
 
-void ast_udptl_get_us(struct ast_udptl *udptl, struct sockaddr_in *us)
+void ast_udptl_get_us(const struct ast_udptl *udptl, struct sockaddr_in *us)
 {
 	memcpy(us, &udptl->us, sizeof(udptl->us));
 }
@@ -893,10 +967,10 @@ void ast_udptl_destroy(struct ast_udptl *udptl)
 
 int ast_udptl_write(struct ast_udptl *s, struct ast_frame *f)
 {
-	int seq;
-	int len;
+	unsigned int seq;
+	unsigned int len;
 	int res;
-	uint8_t buf[LOCAL_FAX_MAX_DATAGRAM * 2];
+	uint8_t buf[s->far_max_datagram];
 
 	/* If we have no peer, return immediately */	
 	if (s->them.sin_addr.s_addr == INADDR_ANY)
@@ -906,11 +980,16 @@ int ast_udptl_write(struct ast_udptl *s, struct ast_frame *f)
 	if (f->datalen == 0)
 		return 0;
 	
-	if (f->frametype != AST_FRAME_MODEM) {
-		ast_log(LOG_WARNING, "UDPTL can only send T.38 data\n");
+	if ((f->frametype != AST_FRAME_MODEM) ||
+	    (f->subclass != AST_MODEM_T38)) {
+		ast_log(LOG_WARNING, "UDPTL can only send T.38 data.\n");
 		return -1;
 	}
 
+	if (f->datalen > s->far_max_ifp) {
+		ast_log(LOG_WARNING, "UDPTL asked to send %d bytes of IFP when far end only prepared to accept %d bytes; data loss may occur.\n", f->datalen, s->far_max_ifp);
+	}
+
 	/* Save seq_no for debug output because udptl_build_packet increments it */
 	seq = s->tx_seq_no & 0xFFFF;
 
@@ -1175,7 +1254,7 @@ static void __ast_udptl_reload(int reload)
 
 	udptlstart = 4500;
 	udptlend = 4999;
-	udptlfectype = 0;
+	udptlfectype = UDPTL_ERROR_CORRECTION_NONE;
 	udptlfecentries = 0;
 	udptlfecspan = 0;
 	udptlmaxdatagram = 0;
@@ -1216,9 +1295,9 @@ static void __ast_udptl_reload(int reload)
 		}
 		if ((s = ast_variable_retrieve(cfg, "general", "T38FaxUdpEC"))) {
 			if (strcmp(s, "t38UDPFEC") == 0)
-				udptlfectype = 2;
+				udptlfectype = UDPTL_ERROR_CORRECTION_FEC;
 			else if (strcmp(s, "t38UDPRedundancy") == 0)
-				udptlfectype = 1;
+				udptlfectype = UDPTL_ERROR_CORRECTION_REDUNDANCY;
 		}
 		if ((s = ast_variable_retrieve(cfg, "general", "T38FaxMaxDatagram"))) {
 			udptlmaxdatagram = atoi(s);