[asterisk-commits] branch oej/securertp-trunk r34062 - in /team/oej/securertp-trunk: ./ apps/ bu...

asterisk-commits at lists.digium.com asterisk-commits at lists.digium.com
Wed Jun 14 01:42:07 MST 2006


Author: oej
Date: Wed Jun 14 03:42:06 2006
New Revision: 34062

URL: http://svn.digium.com/view/asterisk?rev=34062&view=rev
Log:
Resolve conflict, reset automerge, please test

Modified:
    team/oej/securertp-trunk/   (props changed)
    team/oej/securertp-trunk/CREDITS
    team/oej/securertp-trunk/apps/app_rpt.c
    team/oej/securertp-trunk/build_tools/menuselect.h
    team/oej/securertp-trunk/channel.c
    team/oej/securertp-trunk/channels/chan_agent.c
    team/oej/securertp-trunk/channels/chan_sip.c
    team/oej/securertp-trunk/configs/sip.conf.sample
    team/oej/securertp-trunk/configure
    team/oej/securertp-trunk/configure.ac
    team/oej/securertp-trunk/file.c
    team/oej/securertp-trunk/frame.c
    team/oej/securertp-trunk/include/asterisk/autoconfig.h.in
    team/oej/securertp-trunk/include/asterisk/lock.h
    team/oej/securertp-trunk/translate.c

Propchange: team/oej/securertp-trunk/
------------------------------------------------------------------------------
    automerge = http://edvina.net/training/

Propchange: team/oej/securertp-trunk/
------------------------------------------------------------------------------
Binary property 'branch-1.2-merged' - no diff available.

Propchange: team/oej/securertp-trunk/
------------------------------------------------------------------------------
--- svnmerge-integrated (original)
+++ svnmerge-integrated Wed Jun 14 03:42:06 2006
@@ -1,1 +1,1 @@
-/trunk:1-33883
+/trunk:1-34061

Modified: team/oej/securertp-trunk/CREDITS
URL: http://svn.digium.com/view/asterisk/team/oej/securertp-trunk/CREDITS?rev=34062&r1=34061&r2=34062&view=diff
==============================================================================
--- team/oej/securertp-trunk/CREDITS (original)
+++ team/oej/securertp-trunk/CREDITS Wed Jun 14 03:42:06 2006
@@ -26,6 +26,12 @@
 === HARDWARE DONORS === 
 * Thanks to QuickNet Technologies for their donation of an Internet
 PhoneJack and Linejack card to the project.  (http://www.quicknet.net)
+
+* Thanks to VoipSupply for their donation of Sipura ATAs to the project for
+T.38 testing. (http://www.voipsupply.com)
+
+* Thanks to Grandstream for their donation of ATAs to the project for
+T.38 testing. (http://www.grandstream.com)
 
 === MISCELLANEOUS PATCHES ===
 Jim Dixon - Zapata Telephony and app_rpt
@@ -124,6 +130,8 @@
 
 John Martin, Aupix - Improved video support in the SIP channel
 
+Steve Underwood - Provided T.38 pass through support.
+
 === OTHER CONTRIBUTIONS ===
 John Todd - Monkey sounds and associated teletorture prompt
 Michael Jerris - bug marshaling

Modified: team/oej/securertp-trunk/apps/app_rpt.c
URL: http://svn.digium.com/view/asterisk/team/oej/securertp-trunk/apps/app_rpt.c?rev=34062&r1=34061&r2=34062&view=diff
==============================================================================
--- team/oej/securertp-trunk/apps/app_rpt.c (original)
+++ team/oej/securertp-trunk/apps/app_rpt.c Wed Jun 14 03:42:06 2006
@@ -21,7 +21,7 @@
 /*! \file
  *
  * \brief Radio Repeater / Remote Base program 
- *  version 0.47 05/23/06
+ *  version 0.48 06/13/06
  * 
  * \author Jim Dixon, WB6NIL <jim at lambdatel.com>
  *
@@ -123,12 +123,10 @@
 
 /* Un-comment the following to include support for MDC-1200 digital tone
    signalling protocol (using KA6SQG's GPL'ed implementation) */
-/* file must be downloaded separately, not part of Asterisk distribution */
 /* #include "mdc_decode.c" */
 
 /* Un-comment the following to include support for notch filters in the
    rx audio stream (using Tony Fisher's mknotch (mkfilter) implementation) */
-/* file must be downloaded separately, not part of Asterisk distribution */
 /* #include "rpt_notch.c" */
 
 /* maximum digits in DTMF buffer, and seconds after * for DTMF command timeout */
@@ -244,7 +242,7 @@
 #include "asterisk/say.h"
 #include "asterisk/localtime.h"
 
-static  char *tdesc = "Radio Repeater / Remote Base  version 0.47  05/23/2006";
+static  char *tdesc = "Radio Repeater / Remote Base  version 0.48  06/13/2006";
 
 static char *app = "Rpt";
 
@@ -6831,17 +6829,23 @@
 				/* if RX key */
 				if (f->subclass == AST_CONTROL_RADIO_KEY)
 				{
-					if (debug == 7) printf("@@@@ rx key\n");
-					myrpt->keyed = 1;
+					if ((!lasttx) || (myrpt->p.duplex > 1))
+					{
+						if (debug == 7) printf("@@@@ rx key\n");
+						myrpt->keyed = 1;
+					}
 				}
 				/* if RX un-key */
 				if (f->subclass == AST_CONTROL_RADIO_UNKEY)
 				{
-					if (debug == 7) printf("@@@@ rx un-key\n");
-					if(myrpt->keyed) {
-						rpt_telemetry(myrpt,UNKEY,NULL);
+					if ((!lasttx) || (myrpt->p.duplex > 1))
+					{
+						if (debug == 7) printf("@@@@ rx un-key\n");
+						if(myrpt->keyed) {
+							rpt_telemetry(myrpt,UNKEY,NULL);
+						}
+						myrpt->keyed = 0;
 					}
-					myrpt->keyed = 0;
 				}
 			}
 			ast_frfree(f);

Modified: team/oej/securertp-trunk/build_tools/menuselect.h
URL: http://svn.digium.com/view/asterisk/team/oej/securertp-trunk/build_tools/menuselect.h?rev=34062&r1=34061&r2=34062&view=diff
==============================================================================
--- team/oej/securertp-trunk/build_tools/menuselect.h (original)
+++ team/oej/securertp-trunk/build_tools/menuselect.h Wed Jun 14 03:42:06 2006
@@ -53,11 +53,11 @@
 	/*! Default setting */
 	const char *defaultenabled;
 	/*! This module is currently selected */
-	int enabled;
+	unsigned int enabled:1;
 	/*! This module has failed dependencies */
-	int depsfailed;
+	unsigned int depsfailed:1;
 	/*! This module has failed conflicts */
-	int conflictsfailed;
+	unsigned int conflictsfailed:1;
 	/*! dependencies of this module */
 	AST_LIST_HEAD_NOLOCK(, depend) deps;
 	/*! conflicts of this module */
@@ -72,9 +72,9 @@
 	/*! the name displayed in the menu */
 	const char *displayname;
 	/*! Display what is selected, as opposed to not selected */
-	int positive_output;
+	unsigned int positive_output:1;
 	/*! Force a clean of the source tree if anything in this category changes */
-	int force_clean_on_change;
+	unsigned int force_clean_on_change:1;
 	/*! the list of possible values to be set in this variable */
 	AST_LIST_HEAD_NOLOCK(, member) members;
 	/*! for linking */

Modified: team/oej/securertp-trunk/channel.c
URL: http://svn.digium.com/view/asterisk/team/oej/securertp-trunk/channel.c?rev=34062&r1=34061&r2=34062&view=diff
==============================================================================
--- team/oej/securertp-trunk/channel.c (original)
+++ team/oej/securertp-trunk/channel.c Wed Jun 14 03:42:06 2006
@@ -2383,6 +2383,10 @@
 		res = (chan->tech->write_video == NULL) ? 0 :
 			chan->tech->write_video(chan, fr);
 		break;
+	case AST_FRAME_MODEM:
+		res = (chan->tech->write == NULL) ? 0 :
+			chan->tech->write(chan, fr);
+		break;
 	case AST_FRAME_VOICE:
 		if (chan->tech->write == NULL)
 			break;	/*! \todo XXX should return 0 maybe ? */

Modified: team/oej/securertp-trunk/channels/chan_agent.c
URL: http://svn.digium.com/view/asterisk/team/oej/securertp-trunk/channels/chan_agent.c?rev=34062&r1=34061&r2=34062&view=diff
==============================================================================
--- team/oej/securertp-trunk/channels/chan_agent.c (original)
+++ team/oej/securertp-trunk/channels/chan_agent.c Wed Jun 14 03:42:06 2006
@@ -1334,12 +1334,13 @@
 	return chan;
 }
 
-static int powerof(unsigned int v)
-{
-	int x;
-	for (x=0;x<32;x++) {
-		if (v & (1 << x)) return x;
-	}
+static force_inline int powerof(unsigned int d)
+{
+	int x = ffs(d);
+
+	if (x)
+		return x - 1;
+
 	return 0;
 }
 

Modified: team/oej/securertp-trunk/channels/chan_sip.c
URL: http://svn.digium.com/view/asterisk/team/oej/securertp-trunk/channels/chan_sip.c?rev=34062&r1=34061&r2=34062&view=diff
==============================================================================
--- team/oej/securertp-trunk/channels/chan_sip.c (original)
+++ team/oej/securertp-trunk/channels/chan_sip.c Wed Jun 14 03:42:06 2006
@@ -118,6 +118,7 @@
 #include "asterisk/sched.h"
 #include "asterisk/io.h"
 #include "asterisk/rtp.h"
+#include "asterisk/udptl.h"
 #include "asterisk/acl.h"
 #include "asterisk/manager.h"
 #include "asterisk/callerid.h"
@@ -731,9 +732,13 @@
 #define SIP_PAGE2_ALLOWOVERLAP		(1 << 11)	/*!< Allow overlap dialing ? */
 #define SIP_PAGE2_SUBSCRIBEMWIONLY	(1 << 12)	/*!< Only issue MWI notification if subscribed to */
 #define SIP_PAGE2_INC_RINGING		(1 << 13)	/*!< Did this connection increment the counter of in-use calls? */
+#define SIP_PAGE2_T38SUPPORT		(7 << 14)	/*!< T38 Fax Passthrough Support */
+#define SIP_PAGE2_T38SUPPORT_UDPTL	(1 << 14)	/*!< 14: T38 Fax Passthrough Support */
+#define SIP_PAGE2_T38SUPPORT_RTP	(2 << 14)	/*!< 15: T38 Fax Passthrough Support */
+#define SIP_PAGE2_T38SUPPORT_TCP	(4 << 14)	/*!< 16: T38 Fax Passthrough Support */
 
 #define SIP_PAGE2_FLAGS_TO_COPY \
-	(SIP_PAGE2_ALLOWSUBSCRIBE | SIP_PAGE2_ALLOWOVERLAP | SIP_PAGE2_VIDEOSUPPORT)
+	(SIP_PAGE2_ALLOWSUBSCRIBE | SIP_PAGE2_ALLOWOVERLAP | SIP_PAGE2_VIDEOSUPPORT | SIP_PAGE2_T38SUPPORT)
 
 /* SIP packet flags */
 #define SIP_PKT_DEBUG		(1 << 0)	/*!< Debug this packet */
@@ -742,9 +747,54 @@
 #define SIP_PKT_IGNORE_RESP	(1 << 3)	/*!< Resp ignore - ??? */
 #define SIP_PKT_IGNORE_REQ	(1 << 4)	/*!< Req ignore - ??? */
 
+/* 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_TRANSFERED_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 trancoding, 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;
+
 #define sipdebug		ast_test_flag(&global_flags[1], SIP_PAGE2_DEBUG)
 #define sipdebug_config		ast_test_flag(&global_flags[1], SIP_PAGE2_DEBUG_CONFIG)
 #define sipdebug_console	ast_test_flag(&global_flags[1], SIP_PAGE2_DEBUG_CONSOLE)
+
+/*! \brief T38 Sates for a call */
+enum t38state {
+	T38_DISABLED = 0,		/*! Not enabled */
+	T38_LOCAL_DIRECT,		/*! Offered from local */
+	T38_LOCAL_REINVITE,		/*! Offered from local - REINVITE */
+	T38_PEER_DIRECT,		/*! Offered from peer */
+	T38_PEER_REINVITE,		/*! Offered from peer - REINVITE */
+	T38_ENABLED			/*! Negotiated (enabled) */
+};
+
+/*! \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 */
+};
 
 /*! \brief Parameters to know status of transfer */
 enum referstatus {
@@ -850,6 +900,9 @@
 	int noncodeccapability;			/*!< DTMF RFC2833 telephony-event */
 	int redircodecs;			/*!< Redirect codecs */
 	int maxcallbitrate;			/*!< Maximum Call Bitrate for Video Calls */	
+	struct t38properties t38;		/*!< T38 settings */
+	struct sockaddr_in udptlredirip;	/*!< Where our T.38 UDPTL should be going if not to us */
+	struct ast_udptl *udptl;		/*!< T.38 UDPTL session */
 	int callingpres;			/*!< Calling presentation */
 	int authtries;				/*!< Times we've tried to authenticate */
 	int expiry;				/*!< How long we take to expire */
@@ -1423,7 +1476,7 @@
 static struct ast_rtp *sip_get_rtp_peer(struct ast_channel *chan);
 static struct ast_rtp *sip_get_vrtp_peer(struct ast_channel *chan);
 static int sip_get_codec(struct ast_channel *chan);
-static struct ast_frame *sip_rtp_read(struct ast_channel *ast, struct sip_pvt *p);
+static struct ast_frame *sip_rtp_read(struct ast_channel *ast, struct sip_pvt *p, int *faxdetect);
 
 /*----- SRTP interface functions */
 static struct sip_srtp *sip_srtp_alloc(void);
@@ -1435,8 +1488,12 @@
 static int activate_crypto(struct sip_pvt *p, int suite_val, unsigned char *remote_key);
 static int process_crypto(struct sip_pvt *p, const char *attr);
 
-
-
+/*------ T38 Support --------- */
+static int sip_handle_t38_reinvite(struct ast_channel *chan, struct sip_pvt *pvt, int reinvite); /*!< T38 negotiation helper function */
+static int transmit_response_with_t38_sdp(struct sip_pvt *p, char *msg, struct sip_request *req, int retrans);
+static int transmit_reinvite_with_t38_sdp(struct sip_pvt *p);
+static struct ast_udptl *sip_get_udptl_peer(struct ast_channel *chan);
+static int sip_set_udptl_peer(struct ast_channel *chan, struct ast_udptl *udptl);
 
 /*! \brief Definition of this channel for PBX channel registration */
 static const struct ast_channel_tech sip_tech = {
@@ -1478,6 +1535,13 @@
 	get_codec: sip_get_codec,
 };
 
+/*! \brief Interface structure with callbacks used to connect to UDPTL module*/
+static struct ast_udptl_protocol sip_udptl = {
+	type: "SIP",
+	get_udptl_info: sip_get_udptl_peer,
+	set_udptl_peer: sip_set_udptl_peer,
+};
+
 /*! \brief Convert transfer status to string */
 static char *referstatus2str(enum referstatus rstatus)
 {
@@ -2413,6 +2477,24 @@
 		r->vrtp = NULL;
 	}
 	r->prefs = peer->prefs;
+	if (ast_test_flag(&r->flags[1], SIP_PAGE2_T38SUPPORT)) {
+		r->t38.capability = global_t38_capability;
+		if (r->udptl) {
+			if (ast_udptl_get_error_correction_scheme(r->udptl) == UDPTL_ERROR_CORRECTION_FEC )
+				r->t38.capability |= T38FAX_UDP_EC_FEC;
+			else if (ast_udptl_get_error_correction_scheme(r->udptl) == UDPTL_ERROR_CORRECTION_REDUNDANCY )
+				r->t38.capability |= T38FAX_UDP_EC_REDUNDANCY;
+			else if (ast_udptl_get_error_correction_scheme(r->udptl) == UDPTL_ERROR_CORRECTION_NONE )
+				r->t38.capability |= T38FAX_UDP_EC_NONE;
+			r->t38.capability |= T38FAX_RATE_MANAGEMENT_TRANSFERED_TCF;
+			if (option_debug > 1)
+				ast_log(LOG_DEBUG,"Our T38 capability (%d)\n", r->t38.capability);
+		}
+		r->t38.jointcapability = r->t38.capability;
+	} else if (r->udptl) {
+		ast_udptl_destroy(r->udptl);
+		r->udptl = NULL;
+	}
 	natflags = ast_test_flag(&r->flags[0], SIP_NAT) & SIP_NAT_ROUTE;
 	if (r->rtp) {
 		if (option_debug)
@@ -2425,6 +2507,11 @@
 			ast_log(LOG_DEBUG, "Setting NAT on VRTP to %s\n", natflags ? "On" : "Off");
 		ast_rtp_setnat(r->vrtp, natflags);
 		ast_rtp_setdtmf(r->vrtp, 0);
+	}
+	if (r->udptl) {
+		if (option_debug)
+			ast_log(LOG_DEBUG, "Setting NAT on UDPTL to %s\n", natflags ? "On" : "Off");
+		ast_udptl_setnat(r->udptl, natflags);
 	}
 	ast_string_field_set(r, peername, peer->username);
 	ast_string_field_set(r, authname, peer->username);
@@ -2589,6 +2676,7 @@
 		} else if (!strcasecmp(ast_var_name(current),"SIPTRANSFER_REPLACES")) {
 			/* We're replacing a call. */
 			p->options->replaces = ast_var_value(current);
+<<<<<<< .working
 		} else if (!strncasecmp(ast_var_name(current), "SIP_SRTP_SDES", strlen("SIP_SRTP_SDES"))) {
 			if (!ast_srtp_is_registered()) {
 				ast_log(LOG_WARNING, "SIP_SRTP_SDES set but SRTP is not available\n");
@@ -2601,7 +2689,14 @@
 					return -1;
 				}
 			}
-		}
+=======
+		} else if (!strcasecmp(ast_var_name(current),"T38CALL")) {
+			p->t38.state = T38_LOCAL_DIRECT;
+			if (option_debug)
+				ast_log(LOG_DEBUG,"T38State change to %d on channel %s\n", p->t38.state, ast->name);
+>>>>>>> .merge-right.r34043
+		}
+
 	}
 	
 	res = 0;
@@ -2626,6 +2721,9 @@
 	if ( res != -1 ) {
 		p->callingpres = ast->cid.cid_pres;
 		p->jointcapability = p->capability;
+		p->t38.jointcapability = p->t38.capability;
+		if (option_debug)
+			ast_log(LOG_DEBUG,"Our T38 capability (%d), joint T38 capability (%d)\n", p->t38.capability, p->t38.jointcapability);
 		transmit_invite(p, SIP_INVITE, 1, 2);
 		if (p->maxtime) {
 			/* Initialize auto-congest time */
@@ -2693,6 +2791,8 @@
 		ast_rtp_destroy(p->rtp);
 	if (p->vrtp)
 		ast_rtp_destroy(p->vrtp);
+	if (p->udptl)
+		ast_udptl_destroy(p->udptl);
 	if (p->refer)
 		free(p->refer);
 	if (p->route) {
@@ -3225,7 +3325,14 @@
 		ast_setstate(ast, AST_STATE_UP);
 		if (option_debug)
 			ast_log(LOG_DEBUG, "SIP answering channel: %s\n", ast->name);
-		res = transmit_response_with_sdp(p, "200 OK", &p->initreq, XMIT_CRITICAL);
+		if (p->t38.state == T38_PEER_DIRECT) {
+			p->t38.state = T38_ENABLED;
+			if (option_debug > 1)
+				ast_log(LOG_DEBUG,"T38State change to %d on channel %s\n", p->t38.state, ast->name);
+			res = transmit_response_with_t38_sdp(p, "200 OK", &p->initreq, XMIT_CRITICAL);
+		} else {
+			res = transmit_response_with_sdp(p, "200 OK", &p->initreq, XMIT_CRITICAL);
+		}
 	}
 	ast_mutex_unlock(&p->lock);
 	return res;
@@ -3279,6 +3386,21 @@
 		break;
 	case AST_FRAME_IMAGE:
 		return 0;
+		break;
+	case AST_FRAME_MODEM:
+		if (p) {
+			ast_mutex_lock(&p->lock);
+			if (p->udptl) {
+				if ((ast->_state != AST_STATE_UP) &&
+					!ast_test_flag(&p->flags[0], SIP_PROGRESS_SENT) && 
+				    !ast_test_flag(&p->flags[0], SIP_OUTGOING)) {
+					transmit_response_with_t38_sdp(p, "183 Session Progress", &p->initreq, XMIT_RELIABLE);
+					ast_set_flag(&p->flags[0], SIP_PROGRESS_SENT);
+				}
+				res = ast_udptl_write(p->udptl, frame);
+			}
+			ast_mutex_unlock(&p->lock);
+		}
 		break;
 	default: 
 		ast_log(LOG_WARNING, "Can't send %d type frames with SIP write\n", frame->frametype);
@@ -3546,6 +3668,9 @@
 	if (needvideo && i->vrtp) {
 		tmp->fds[2] = ast_rtp_fd(i->vrtp);
 		tmp->fds[3] = ast_rtcp_fd(i->vrtp);
+	}
+	if (i->udptl) {
+		tmp->fds[5] = ast_udptl_fd(i->udptl);
 	}
 	if (state == AST_STATE_RING)
 		tmp->rings = 1;
@@ -3740,7 +3865,7 @@
 }
 
 /*! \brief Read RTP from network */
-static struct ast_frame *sip_rtp_read(struct ast_channel *ast, struct sip_pvt *p)
+static struct ast_frame *sip_rtp_read(struct ast_channel *ast, struct sip_pvt *p, int *faxdetect)
 {
 	/* Retrieve audio/etc from channel.  Assumes p->lock is already held. */
 	struct ast_frame *f;
@@ -3763,6 +3888,9 @@
 	case 3:
 		f = ast_rtcp_read(p->vrtp);	/* RTCP Control Channel for video */
 		break;
+	case 5:
+		f = ast_udptl_read(p->udptl);	/* UDPTL for T.38 */
+		break;
 	default:
 		f = &ast_null_frame;
 	}
@@ -3783,8 +3911,15 @@
 			}
 			if ((ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_INBAND) && p->vad) {
 				f = ast_dsp_process(p->owner, p->vad, f);
-				if (option_debug && f && (f->frametype == AST_FRAME_DTMF)) 
-					ast_log(LOG_DEBUG, "* Detected inband DTMF '%c'\n", f->subclass);
+				if (f && f->frametype == AST_FRAME_DTMF) {
+					if (ast_test_flag(&p->t38.t38support, SIP_PAGE2_T38SUPPORT_UDPTL) && f->subclass == 'f') {
+						if (option_debug)
+							ast_log(LOG_DEBUG, "Fax CNG detected on %s\n", ast->name);
+						*faxdetect = 1;
+					} else if (option_debug) {
+						ast_log(LOG_DEBUG, "* Detected inband DTMF '%c'\n", f->subclass);
+					}
+				}
 			}
 		}
 	}
@@ -3796,10 +3931,31 @@
 {
 	struct ast_frame *fr;
 	struct sip_pvt *p = ast->tech_pvt;
+	int faxdetected = 0;
 
 	ast_mutex_lock(&p->lock);
-	fr = sip_rtp_read(ast, p);
+	fr = sip_rtp_read(ast, p, &faxdetected);
 	p->lastrtprx = time(NULL);
+
+	/* 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_UDPTL) && (p->t38.state == T38_DISABLED) && !(ast_bridged_channel(ast))) {
+		if (!ast_test_flag(&p->flags[0], SIP_GOTREFER)) {
+			if (!p->pendinginvite) {
+				if (option_debug > 2)
+					ast_log(LOG_DEBUG, "Sending reinvite on SIP (%s) for T.38 negotiation.\n",ast->name);
+				p->t38.state = T38_LOCAL_REINVITE;
+				transmit_reinvite_with_t38_sdp(p);
+				if (option_debug > 1)
+					ast_log(LOG_DEBUG, "T38 state changed to %d on channel %s", p->t38.state, ast->name);
+			}
+		} else if (!ast_test_flag(&p->flags[0], SIP_PENDINGBYE)) {
+			if (option_debug > 2)
+				ast_log(LOG_DEBUG, "Deferring reinvite on SIP (%s) - it will be re-negotiated for T.38\n", ast->name);
+			ast_set_flag(&p->flags[0], SIP_NEEDREINVITE);
+		}
+	}
+
 	ast_mutex_unlock(&p->lock);
 	return fr;
 }
@@ -3893,6 +4049,8 @@
 		/* If the global videosupport flag is on, we always create a RTP interface for video */
 		if (ast_test_flag(&p->flags[1], SIP_PAGE2_VIDEOSUPPORT))
 			p->vrtp = ast_rtp_new_with_bindaddr(sched, io, 1, 0, bindaddr.sin_addr);
+		if (ast_test_flag(&p->flags[1], SIP_PAGE2_T38SUPPORT))
+			p->udptl = ast_udptl_new_with_bindaddr(sched, io, 0, bindaddr.sin_addr);
 		if (!p->rtp || (ast_test_flag(&p->flags[1], SIP_PAGE2_VIDEOSUPPORT) && !p->vrtp)) {
 			ast_log(LOG_WARNING, "Unable to create RTP audio %s session: %s\n",
 				ast_test_flag(&p->flags[1], SIP_PAGE2_VIDEOSUPPORT) ? "and video" : "", strerror(errno));
@@ -3909,6 +4067,9 @@
 		if (p->vrtp) {
 			ast_rtp_settos(p->vrtp, global_tos_video);
 			ast_rtp_setdtmf(p->vrtp, 0);
+		}
+		if (p->udptl) {
+			ast_udptl_settos(p->udptl, global_tos_audio);
 		}
 		p->rtptimeout = global_rtptimeout;
 		p->rtpholdtimeout = global_rtpholdtimeout;
@@ -3926,6 +4087,8 @@
 			ast_rtp_setnat(p->rtp, natflags);
 		if (p->vrtp)
 			ast_rtp_setnat(p->vrtp, natflags);
+		if (p->udptl)
+			ast_udptl_setnat(p->udptl, natflags);
 	}
 
 	if (p->method != SIP_REGISTER)
@@ -3942,6 +4105,17 @@
 	if ((ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_RFC2833) ||
 	    (ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_AUTO))
 		p->noncodeccapability |= AST_RTP_DTMF;
+	if (p->udptl) {
+		p->t38.capability = global_t38_capability;
+		if (ast_udptl_get_error_correction_scheme(p->udptl) == UDPTL_ERROR_CORRECTION_REDUNDANCY)
+			p->t38.capability |= T38FAX_UDP_EC_REDUNDANCY;
+		else if (ast_udptl_get_error_correction_scheme(p->udptl) == UDPTL_ERROR_CORRECTION_FEC)
+			p->t38.capability |= T38FAX_UDP_EC_FEC;
+		else if (ast_udptl_get_error_correction_scheme(p->udptl) == UDPTL_ERROR_CORRECTION_NONE)
+			p->t38.capability |= T38FAX_UDP_EC_NONE;
+		p->t38.capability |= T38FAX_RATE_MANAGEMENT_TRANSFERED_TCF;
+		p->t38.jointcapability = p->t38.capability;
+	}
 	ast_string_field_set(p, context, default_context);
 
 	/* Add to active dialog list */
@@ -4299,6 +4473,10 @@
 	int len = -1;
 	int portno = -1;		/*!< RTP Audio port number */
 	int vportno = -1;		/*!< RTP Video port number */
+	int udptlportno = -1;
+	int peert38capability = 0;
+	char s[256];
+	int old = 0;
 
 	/* Peer capability is the capability in the SDP, non codec is RFC2833 DTMF (101) */	
 	int peercapability, peernoncodeccapability;
@@ -4434,6 +4612,20 @@
 					ast_verbose("Found RTP video format %d\n", codec);
 				ast_rtp_set_m_type(newvideortp, codec);
 			}
+		} else if (p->udptl && (sscanf(m, "image %d udptl t38 %n", &x, &len) == 1)) {
+			if (debug)
+				ast_verbose("Got T.38 offer in SDP\n");
+			udptlportno = x;
+			
+			if (p->owner && p->lastinvite) {
+				p->t38.state = T38_PEER_REINVITE; /* T38 Offered in re-invite from remote party */
+				if (option_debug > 1)
+					ast_log(LOG_DEBUG, "T38 state changed to %d on channel %s\n", p->t38.state, p->owner ? p->owner->name : "<none>" );
+			} else {
+				p->t38.state = T38_PEER_DIRECT; /* T38 Offered directly from peer in first invite */
+				if (option_debug > 1)
+					ast_log(LOG_DEBUG, "T38 state changed to %d on channel %s\n", p->t38.state, p->owner ? p->owner->name : "<none>");
+			}
 		} else 
 			ast_log(LOG_WARNING, "Unsupported SDP media type in offer: %s\n", m);
 		if (numberofports > 1)
@@ -4456,7 +4648,7 @@
 
 		}
 	}
-	if (portno == -1 && vportno == -1)
+	if (portno == -1 && vportno == -1 && udptlportno == -1)
 		/* No acceptable offer found in SDP  - we have no ports */
 		/* Do not change RTP or VRTP if this is a re-invite */
 		return -2;
@@ -4472,12 +4664,35 @@
 	if (vhp)
 		memcpy(&vsin.sin_addr, vhp->h_addr, sizeof(vsin.sin_addr));
 		
-
-	/* Setup audio port number */
-	sin.sin_port = htons(portno);
+	if (p->rtp) {
+		if (portno > 0) {
+			sin.sin_port = htons(portno);
+			ast_rtp_set_peer(p->rtp, &sin);
+			if (debug)
+				ast_verbose("Peer audio RTP is at port %s:%d\n", ast_inet_ntoa(iabuf,sizeof(iabuf), sin.sin_addr), ntohs(sin.sin_port));
+		} else {
+			ast_rtp_stop(p->rtp);
+			if (debug)
+				ast_verbose("Peer doesn't provide audio\n");
+		}
+	}
 	/* Setup video port number */
 	if (vportno != -1)
 		vsin.sin_port = htons(vportno);
+
+	/* Setup UDPTL port number */
+	if (p->udptl) {
+		if (udptlportno > 0) {
+			sin.sin_port = htons(udptlportno);
+			ast_udptl_set_peer(p->udptl, &sin);
+			if (debug)
+				ast_log(LOG_DEBUG,"Peer T.38 UDPTL is at port %s:%d\n",ast_inet_ntoa(iabuf, sizeof(iabuf), sin.sin_addr), ntohs(sin.sin_port));
+		} else {
+			ast_udptl_stop(p->udptl);
+			if (debug)
+				ast_log(LOG_DEBUG, "Peer doesn't provide T.38 UDPTL\n");
+		}
+	}
 
 	/* Next, scan through each "a=rtpmap:" line, noting each
 	 * specified RTP payload type (with corresponding MIME subtype):
@@ -4549,6 +4764,123 @@
 			return -2;
 		}
 	}
+	
+	if (udptlportno != -1) {
+		int found = 0, x;
+		
+		old = 0;
+		
+		/* Scan trough the a= lines for T38 attributes and set apropriate fileds */
+		iterator = req->sdp_start;
+		while ((a = get_sdp_iterate(&iterator, req, "a"))[0] != '\0') {
+			if ((sscanf(a, "T38FaxMaxBuffer:%d", &x) == 1)) {
+				found = 1;
+				if (option_debug > 2)
+					ast_log(LOG_DEBUG,"MaxBufferSize:%d\n",x);
+			}
+			if ((sscanf(a, "T38MaxBitRate:%d", &x) == 1)) {
+				found = 1;
+				if (option_debug > 2)
+					ast_log(LOG_DEBUG,"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;
+					break;
+				case 12000:
+					peert38capability |= T38FAX_RATE_12000 | T38FAX_RATE_9600 | T38FAX_RATE_7200 | T38FAX_RATE_4800 | T38FAX_RATE_2400;
+					break;
+				case 9600:
+					peert38capability |= T38FAX_RATE_9600 | T38FAX_RATE_7200 | T38FAX_RATE_4800 | T38FAX_RATE_2400;
+					break;
+				case 7200:
+					peert38capability |= T38FAX_RATE_7200 | T38FAX_RATE_4800 | T38FAX_RATE_2400;
+					break;
+				case 4800:
+					peert38capability |= T38FAX_RATE_4800 | T38FAX_RATE_2400;
+					break;
+				case 2400:
+					peert38capability |= T38FAX_RATE_2400;
+					break;
+				}
+			}
+			if ((sscanf(a, "T38FaxVersion:%d", &x) == 1)) {
+				found = 1;
+				if (option_debug > 2)
+					ast_log(LOG_DEBUG,"FaxVersion: %d\n",x);
+				if (x == 0)
+					peert38capability |= T38FAX_VERSION_0;
+				else if (x == 1)
+					peert38capability |= T38FAX_VERSION_1;
+			}
+			if ((sscanf(a, "T38FaxMaxDatagram:%d", &x) == 1)) {
+				found = 1;
+				if (option_debug > 2)
+					ast_log(LOG_DEBUG,"FaxMaxDatagram: %d\n",x);
+				ast_udptl_set_far_max_datagram(p->udptl, x);
+				ast_udptl_set_local_max_datagram(p->udptl, x);
+			}
+			if ((sscanf(a, "T38FaxFillBitRemoval:%d", &x) == 1)) {
+				found = 1;
+				if (option_debug > 2)
+					ast_log(LOG_DEBUG,"FillBitRemoval: %d\n",x);
+				if (x == 1)
+					peert38capability |= T38FAX_FILL_BIT_REMOVAL;
+			}
+			if ((sscanf(a, "T38FaxTranscodingMMR:%d", &x) == 1)) {
+				found = 1;
+				if (option_debug > 2)
+					ast_log(LOG_DEBUG,"Transcoding MMR: %d\n",x);
+				if (x == 1)
+					peert38capability |= T38FAX_TRANSCODING_MMR;
+			}
+			if ((sscanf(a, "T38FaxTranscodingJBIG:%d", &x) == 1)) {
+				found = 1;
+				if (option_debug > 2)
+					ast_log(LOG_DEBUG,"Transcoding JBIG: %d\n",x);
+				if (x == 1)
+					peert38capability |= T38FAX_TRANSCODING_JBIG;
+			}
+			if ((sscanf(a, "T38FaxRateManagement:%s", s) == 1)) {
+				found = 1;
+				if (option_debug > 2)
+					ast_log(LOG_DEBUG,"RateMangement: %s\n", s);
+				if (!strcasecmp(s, "localTCF"))
+					peert38capability |= T38FAX_RATE_MANAGEMENT_LOCAL_TCF;
+				else if (!strcasecmp(s, "transferredTCF"))
+					peert38capability |= T38FAX_RATE_MANAGEMENT_TRANSFERED_TCF;
+			}
+			if ((sscanf(a, "T38FaxUdpEC:%s", s) == 1)) {
+				found = 1;
+				if (option_debug > 2)
+					ast_log(LOG_DEBUG,"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_log(LOG_DEBUG,"Our T38 capability = (%d), peer T38 capability (%d), joint T38 capability (%d)\n",
+				p->t38.capability,
+				p->t38.peercapability,
+				p->t38.jointcapability);
+	} else {
+		p->t38.state = T38_DISABLED;
+		if (option_debug > 1)
+			ast_log(LOG_DEBUG, "T38 state changed to %d on channel %s\n", p->t38.state, p->owner ? p->owner->name : "<none>");
+	}
 
 	/* Now gather all of the codecs that we are asked for: */
 	ast_rtp_get_current_formats(newaudiortp, &peercapability, &peernoncodeccapability);
@@ -5284,6 +5616,142 @@
 		ast_build_string(a_buf, a_size, "a=fmtp:%d annexb=no\r\n", rtp_code);
 }
 
+/*! \brief Get Max T.38 Transmision rate from T38 capabilities */
+static int t38_get_rate(int t38cap)
+{
+	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) {
+		if (option_debug > 1)
+			ast_log(LOG_DEBUG, "T38MaxFaxRate 14400 found\n");
+		return 14400;
+	} else if (maxrate & T38FAX_RATE_12000) {
+		if (option_debug > 1)
+			ast_log(LOG_DEBUG, "T38MaxFaxRate 12000 found\n");
+		return 12000;
+	} else if (maxrate & T38FAX_RATE_9600) {
+		if (option_debug > 1)
+			ast_log(LOG_DEBUG, "T38MaxFaxRate 9600 found\n");
+		return 9600;
+	} else if (maxrate & T38FAX_RATE_7200) {
+		if (option_debug > 1)
+			ast_log(LOG_DEBUG, "T38MaxFaxRate 7200 found\n");
+		return 7200;
+	} else if (maxrate & T38FAX_RATE_4800) {
+		if (option_debug > 1)
+			ast_log(LOG_DEBUG, "T38MaxFaxRate 4800 found\n");
+		return 4800;
+	} else if (maxrate & T38FAX_RATE_2400) {
+		if (option_debug > 1)
+			ast_log(LOG_DEBUG, "T38MaxFaxRate 2400 found\n");
+		return 2400;
+	} else {
+		if (option_debug > 1)
+			ast_log(LOG_DEBUG, "Strange, T38MaxFaxRate NOT found in peers T38 SDP.\n");
+		return 0;
+	}
+}
+
+/*! \brief Add T.38 Session Description Protocol message */
+static int add_t38_sdp(struct sip_request *resp, struct sip_pvt *p)
+{
+	int len = 0;
+	int x = 0;
+	struct sockaddr_in udptlsin;
+	char v[256] = "";
+	char s[256] = "";
+	char o[256] = "";
+	char c[256] = "";
+	char t[256] = "";
+	char m_modem[256];
+	char a_modem[1024];
+	char *m_modem_next = m_modem;
+	size_t m_modem_left = sizeof(m_modem);
+	char *a_modem_next = a_modem;
+	size_t a_modem_left = sizeof(a_modem);
+	char iabuf[INET_ADDRSTRLEN];
+	struct sockaddr_in udptldest = { 0, };
+	int debug;
+	
+	debug = sip_debug_test_pvt(p);
+	len = 0;
+	if (!p->udptl) {
+		ast_log(LOG_WARNING, "No way to add SDP without an UDPTL structure\n");
+		return -1;
+	}
+	
+	if (!p->sessionid) {
+		p->sessionid = getpid();
+		p->sessionversion = p->sessionid;
+	} else
+		p->sessionversion++;
+	
+	/* Our T.38 end is */
+	ast_udptl_get_us(p->udptl, &udptlsin);
+	
+	/* Determine T.38 UDPTL destination */
+	if (p->udptlredirip.sin_addr.s_addr) {
+		udptldest.sin_port = p->udptlredirip.sin_port;
+		udptldest.sin_addr = p->udptlredirip.sin_addr;
+	} else {
+		udptldest.sin_addr = p->ourip;
+		udptldest.sin_port = udptlsin.sin_port;
+	}
+	
+	if (debug) {
+		ast_log(LOG_DEBUG, "T.38 UDPTL is at %s port %d\n", ast_inet_ntoa(iabuf, sizeof(iabuf), p->ourip), ntohs(udptlsin.sin_port));
+	}
+	
+	/* We break with the "recommendation" and send our IP, in order that our
+	   peer doesn't have to ast_gethostbyname() us */
+	
+	if (debug) {
+		ast_log(LOG_DEBUG, "Our T38 capability (%d), peer T38 capability (%d), joint capability (%d)\n",
+			p->t38.capability,
+			p->t38.peercapability,
+			p->t38.jointcapability);
+	}
+	snprintf(v, sizeof(v), "v=0\r\n");
+	snprintf(o, sizeof(o), "o=root %d %d IN IP4 %s\r\n", p->sessionid, p->sessionversion, ast_inet_ntoa(iabuf, sizeof(iabuf), udptldest.sin_addr));
+	snprintf(s, sizeof(s), "s=session\r\n");
+	snprintf(c, sizeof(c), "c=IN IP4 %s\r\n", ast_inet_ntoa(iabuf, sizeof(iabuf), udptldest.sin_addr));
+	snprintf(t, sizeof(t), "t=0 0\r\n");
+	ast_build_string(&m_modem_next, &m_modem_left, "m=image %d udptl t38\r\n", ntohs(udptldest.sin_port));
+	
+	if ((p->t38.jointcapability & T38FAX_VERSION) == T38FAX_VERSION_0)
+		ast_build_string(&a_modem_next, &a_modem_left, "a=T38FaxVersion:0\r\n");
+	if ((p->t38.jointcapability & T38FAX_VERSION) == T38FAX_VERSION_1)
+		ast_build_string(&a_modem_next, &a_modem_left, "a=T38FaxVersion:1\r\n");
+	if ((x = t38_get_rate(p->t38.jointcapability)))
+		ast_build_string(&a_modem_next, &a_modem_left, "a=T38MaxBitRate:%d\r\n",x);
+	ast_build_string(&a_modem_next, &a_modem_left, "a=T38FaxFillBitRemoval:%d\r\n", (p->t38.jointcapability & T38FAX_FILL_BIT_REMOVAL) ? 1 : 0);
+	ast_build_string(&a_modem_next, &a_modem_left, "a=T38FaxTranscodingMMR:%d\r\n", (p->t38.jointcapability & T38FAX_TRANSCODING_MMR) ? 1 : 0);
+	ast_build_string(&a_modem_next, &a_modem_left, "a=T38FaxTranscodingJBIG:%d\r\n", (p->t38.jointcapability & T38FAX_TRANSCODING_JBIG) ? 1 : 0);
+	ast_build_string(&a_modem_next, &a_modem_left, "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_build_string(&a_modem_next, &a_modem_left, "a=T38FaxMaxBuffer:%d\r\n",x);
+	ast_build_string(&a_modem_next, &a_modem_left, "a=T38FaxMaxDatagram:%d\r\n",x);
+	if (p->t38.jointcapability != T38FAX_UDP_EC_NONE)
+		ast_build_string(&a_modem_next, &a_modem_left, "a=T38FaxUdpEC:%s\r\n", (p->t38.jointcapability & T38FAX_UDP_EC_REDUNDANCY) ? "t38UDPRedundancy" : "t38UDPFEC");
+	if (p->udptl)
+		len = strlen(m_modem) + strlen(a_modem);
+	add_header(resp, "Content-Type", "application/sdp");
+	add_header_contentLength(resp, len);
+	add_line(resp, v);
+	add_line(resp, o);
+	add_line(resp, s);
+	add_line(resp, c);
+	add_line(resp, t);
+	add_line(resp, m_modem);
+	add_line(resp, a_modem);
+	
+	/* Update lastrtprx when we send our SDP */
+	p->lastrtprx = p->lastrtptx = time(NULL);
+	
+	return 0;
+}
+
+
 /*! \brief Add RFC 2833 DTMF offer to SDP */
 static void add_noncodec_to_sdp(const struct sip_pvt *p, int format, int sample_rate,
 				char **m_buf, size_t *m_size, char **a_buf, size_t *a_size,
@@ -5385,6 +5853,11 @@
 		ast_log(LOG_DEBUG, "** Our capability: %s Video flag: %s\n", ast_getformatname_multiple(codecbuf, sizeof(codecbuf), capability), ast_test_flag(&p->flags[0], SIP_NOVIDEO) ? "True" : "False");
 		ast_log(LOG_DEBUG, "** Our prefcodec: %s \n", ast_getformatname_multiple(codecbuf, sizeof(codecbuf), p->prefcodec));
 	}
+	
+	if ((ast_test_flag(&p->t38.t38support, SIP_PAGE2_T38SUPPORT_RTP))) {
+		ast_build_string(&m_audio_next, &m_audio_left, " %d", 191);
+		ast_build_string(&a_audio_next, &a_audio_left, "a=rtpmap:%d %s/%d\r\n", 191, "t38", 8000);
+	}
 
 	/* Check if we need video in this call */
 	if((capability & AST_FORMAT_VIDEO_MASK) && !ast_test_flag(&p->flags[0], SIP_NOVIDEO)) {
@@ -5598,6 +6071,26 @@
 	return 0;
 }
 
+/*--- transmit_response_with_t38_sdp: Used for 200 OK and 183 early media ---*/
+static int transmit_response_with_t38_sdp(struct sip_pvt *p, char *msg, struct sip_request *req, int retrans)
+{
+	struct sip_request resp;
+	int seqno;
+	
+	if (sscanf(get_header(req, "CSeq"), "%d ", &seqno) != 1) {
+		ast_log(LOG_WARNING, "Unable to get seqno from '%s'\n", get_header(req, "CSeq"));
+		return -1;
+	}
+	respprep(&resp, p, msg, req);
+	if (p->udptl) {
+		ast_udptl_offered_from_local(p->udptl, 0);
+		add_t38_sdp(&resp, p);
+	} else {
+		ast_log(LOG_ERROR, "Can't add SDP to response, since we have no UDPTL session allocated. Call-ID %s\n", p->callid);
+	}
+	return send_response(p, &resp, retrans, seqno);
+}
+
 /*! \brief copy SIP request (mostly used to save request for responses) */
 static void copy_request(struct sip_request *dst, const struct sip_request *src)
 {
@@ -5692,6 +6185,31 @@
 	if (recordhistory)
 		append_history(p, "ReInv", "Re-invite sent");
 	add_sdp(&req, p);
+	/* Use this as the basis */
+	initialize_initreq(p, &req);
+	p->lastinvite = p->ocseq;
+	ast_set_flag(&p->flags[0], SIP_OUTGOING);
+	return send_request(p, &req, 1, p->ocseq);
+}
+
+/*--- transmit_reinvite_with_t38_sdp: Transmit reinvite with T38 SDP ---*/
+/*     A re-invite is basically a new INVITE with the same CALL-ID and TAG as the
+       INVITE that opened the SIP dialogue
+       We reinvite so that the T38 processing can take place.
+       SIP Signalling stays with * in the path.
+*/
+static int transmit_reinvite_with_t38_sdp(struct sip_pvt *p)
+{
+	struct sip_request req;
+
+	reqprep(&req, p, ast_test_flag(&p->flags[0], SIP_REINVITE_UPDATE) ?  SIP_UPDATE : SIP_INVITE, 0, 1);
+	
+	add_header(&req, "Allow", ALLOWED_METHODS);
+	add_header(&req, "Supported", SUPPORTED_EXTENSIONS);
+	if (sipdebug)
+		add_header(&req, "X-asterisk-info", "SIP re-invite (T38 switchover)");
+	ast_udptl_offered_from_local(p->udptl, 1);
+	add_t38_sdp(&req, p);
 	/* Use this as the basis */
 	initialize_initreq(p, &req);
 	p->lastinvite = p->ocseq;
@@ -6028,8 +6546,15 @@
 			}
 		}
 	}
-	if (sdp && p->rtp) {
-		add_sdp(&req, p);
+	if (sdp) {
+		if (p->udptl && p->t38.state == T38_LOCAL_DIRECT) {
+			ast_udptl_offered_from_local(p->udptl, 1);
+			if (option_debug)
+				ast_log(LOG_DEBUG, "T38 is in state %d on channel %s\n", p->t38.state, p->owner ? p->owner->name : "<none>");
+			add_t38_sdp(&req, p);
+		} else if (p->rtp) {
+			add_sdp(&req, p);
+		}
 	} else {
 		add_header_contentLength(&req, 0);
 	}
@@ -8181,6 +8706,11 @@
 				ast_log(LOG_DEBUG, "Setting NAT on VRTP to %s\n", usenatroute ? "On" : "Off");
 			ast_rtp_setnat(p->vrtp, usenatroute);
 		}
+		if (p->udptl) {
+			if (option_debug)
+				ast_log(LOG_DEBUG, "Setting NAT on UDPTL to %s\n", usenatroute ? "On" : "Off");
+			ast_udptl_setnat(p->udptl, usenatroute);
+		}
 		if (!(res = check_auth(p, req, user->name, user->secret, user->md5secret, sipmethod, uri, reliable, ast_test_flag(req, SIP_PKT_IGNORE)))) {
 			sip_cancel_destroy(p);
 			ast_copy_flags(&p->flags[0], &user->flags[0], SIP_FLAGS_TO_COPY);
@@ -8227,7 +8757,8 @@

[... 746 lines stripped ...]


More information about the asterisk-commits mailing list