adds support for t38 pass through patch brought up to trunk from
authorMatt O'Gorman <mogorman@digium.com>
Tue, 13 Jun 2006 18:35:53 +0000 (18:35 +0000)
committerMatt O'Gorman <mogorman@digium.com>
Tue, 13 Jun 2006 18:35:53 +0000 (18:35 +0000)
bug 5090 by josh colp.  Thanks to everyone who help get this patch through
especially to the author Steven Underwood.

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@33890 65c4cc65-6c06-0410-ace0-fbb531ad65f3

channel.c
channels/chan_sip.c

index 398bf59..30a1ad0 100644 (file)
--- a/channel.c
+++ b/channel.c
@@ -2383,6 +2383,10 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr)
                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 ? */
index 5f60081..49b8aac 100644 (file)
@@ -118,6 +118,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #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"
@@ -718,9 +719,13 @@ struct sip_auth {
 #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 */
@@ -729,10 +734,55 @@ struct sip_auth {
 #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 {
        REFER_IDLE,             /*!< No REFER is in progress */
@@ -837,6 +887,9 @@ static struct sip_pvt {
        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 */
@@ -1409,8 +1462,14 @@ static int sip_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp, struc
 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);
 
+/*------ 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 = {
@@ -1452,6 +1511,13 @@ static struct ast_rtp_protocol sip_rtp = {
        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)
 {
@@ -2387,6 +2453,24 @@ static int create_addr_from_peer(struct sip_pvt *r, struct sip_peer *peer)
                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)
@@ -2400,6 +2484,11 @@ static int create_addr_from_peer(struct sip_pvt *r, struct sip_peer *peer)
                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);
        ast_string_field_set(r, username, peer->username);
@@ -2563,7 +2652,12 @@ static int sip_call(struct ast_channel *ast, char *dest, int timeout)
                } else if (!strcasecmp(ast_var_name(current),"SIPTRANSFER_REPLACES")) {
                        /* We're replacing a call. */
                        p->options->replaces = ast_var_value(current);
+               } 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);
                }
+
        }
        
        res = 0;
@@ -2588,6 +2682,9 @@ static int sip_call(struct ast_channel *ast, char *dest, int timeout)
        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 */
@@ -2655,6 +2752,8 @@ static void __sip_destroy(struct sip_pvt *p, int lockowner)
                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) {
@@ -3182,7 +3281,14 @@ static int sip_answer(struct ast_channel *ast)
                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;
@@ -3237,6 +3343,21 @@ static int sip_write(struct ast_channel *ast, struct ast_frame *frame)
        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);
                return 0;
@@ -3504,6 +3625,9 @@ static struct ast_channel *sip_new(struct sip_pvt *i, int state, const char *tit
                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;
        tmp->adsicpe = AST_ADSI_UNAVAILABLE;
@@ -3697,7 +3821,7 @@ static const char *get_header(const struct sip_request *req, const char *name)
 }
 
 /*! \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;
@@ -3720,6 +3844,9 @@ static struct ast_frame *sip_rtp_read(struct ast_channel *ast, struct sip_pvt *p
        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;
        }
@@ -3740,8 +3867,15 @@ static struct ast_frame *sip_rtp_read(struct ast_channel *ast, struct sip_pvt *p
                        }
                        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);
+                                       }
+                               }
                        }
                }
        }
@@ -3753,10 +3887,31 @@ static struct ast_frame *sip_read(struct ast_channel *ast)
 {
        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;
 }
@@ -3850,6 +4005,8 @@ static struct sip_pvt *sip_alloc(ast_string_field callid, struct sockaddr_in *si
                /* 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));
@@ -3867,6 +4024,9 @@ static struct sip_pvt *sip_alloc(ast_string_field callid, struct sockaddr_in *si
                        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;
                p->rtpkeepalive = global_rtpkeepalive;
@@ -3883,6 +4043,8 @@ static struct sip_pvt *sip_alloc(ast_string_field callid, struct sockaddr_in *si
                        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)
@@ -3899,6 +4061,17 @@ static struct sip_pvt *sip_alloc(ast_string_field callid, struct sockaddr_in *si
        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 */
@@ -4256,6 +4429,10 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req)
        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;
@@ -4366,6 +4543,20 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req)
                                        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)
@@ -4388,7 +4579,7 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req)
 
                }
        }
-       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;
@@ -4404,13 +4595,36 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req)
        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):
         */
@@ -4474,6 +4688,123 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req)
                if (p->vrtp)
                        ast_rtp_set_rtpmap_type(newvideortp, codec, "video", mimeSubtype);
        }
+       
+       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);
@@ -5209,6 +5540,142 @@ static void add_codec_to_sdp(const struct sip_pvt *p, int codec, int sample_rate
                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,
@@ -5306,6 +5773,11 @@ static int add_sdp(struct sip_request *resp, struct sip_pvt *p)
                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)) {
@@ -5494,6 +5966,26 @@ static int add_sdp(struct sip_request *resp, struct sip_pvt *p)
        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)
 {
@@ -5595,6 +6087,31 @@ static int transmit_reinvite_with_sdp(struct sip_pvt *p)
        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;
+       ast_set_flag(&p->flags[0], SIP_OUTGOING);
+       return send_request(p, &req, 1, p->ocseq);
+}
+
 /*! \brief Check Contact: URI of SIP message */
 static void extract_uri(struct sip_pvt *p, struct sip_request *req)
 {
@@ -5924,8 +6441,15 @@ static int transmit_invite(struct sip_pvt *p, int sipmethod, int sdp, int init)
                        }
                }
        }
-       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);
        }
@@ -8077,6 +8601,11 @@ static enum check_auth_result check_user_full(struct sip_pvt *p, struct sip_requ
                                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);
@@ -8123,7 +8652,8 @@ static enum check_auth_result check_user_full(struct sip_pvt *p, struct sip_requ
                                p->noncodeccapability |= AST_RTP_DTMF;
                        else
                                p->noncodeccapability &= ~AST_RTP_DTMF;
-
+                       if (p->t38.peercapability)
+                               p->t38.jointcapability &= p->t38.peercapability;
                        p->maxcallbitrate = user->maxcallbitrate;
                        /* If we do not support video, remove video from call structure */
                        if (!ast_test_flag(&p->flags[1], SIP_PAGE2_VIDEOSUPPORT) && p->vrtp) {
@@ -8184,6 +8714,10 @@ static enum check_auth_result check_user_full(struct sip_pvt *p, struct sip_requ
                                ast_log(LOG_DEBUG, "Setting NAT on VRTP to %s\n", usenatroute ? "On" : "Off");
                                ast_rtp_setnat(p->vrtp, usenatroute);
                        }
+                       if (p->udptl) {
+                               ast_log(LOG_DEBUG, "Setting NAT on UDPTL to %s\n", usenatroute ? "On" : "Off");
+                               ast_udptl_setnat(p->udptl, usenatroute);
+                       }
                        ast_string_field_set(p, peersecret, peer->secret);
                        ast_string_field_set(p, peermd5secret, peer->md5secret);
                        ast_string_field_set(p, subscribecontext, peer->subscribecontext);
@@ -8255,6 +8789,8 @@ static enum check_auth_result check_user_full(struct sip_pvt *p, struct sip_requ
                                        p->noncodeccapability |= AST_RTP_DTMF;
                                else
                                        p->noncodeccapability &= ~AST_RTP_DTMF;
+                               if (p->t38.peercapability)
+                                       p->t38.jointcapability &= p->t38.peercapability;
                        }
                        ASTOBJ_UNREF(peer, sip_destroy_peer);
                } else { 
@@ -9055,6 +9591,9 @@ static int _sip_show_peer(int type, int fd, struct mansession *s, struct message
                ast_cli(fd, "  Insecure     : %s\n", insecure2str(ast_test_flag(&peer->flags[0], SIP_INSECURE_PORT), ast_test_flag(&peer->flags[0], SIP_INSECURE_INVITE)));
                ast_cli(fd, "  Nat          : %s\n", nat2str(ast_test_flag(&peer->flags[0], SIP_NAT)));
                ast_cli(fd, "  ACL          : %s\n", (peer->ha?"Yes":"No"));
+               ast_cli(fd, "  T38 pt UDPTL : %s\n", ast_test_flag(&peer->flags[1], SIP_PAGE2_T38SUPPORT_UDPTL)?"Yes":"No");
+               ast_cli(fd, "  T38 pt RTP   : %s\n", ast_test_flag(&peer->flags[1], SIP_PAGE2_T38SUPPORT_RTP)?"Yes":"No");
+               ast_cli(fd, "  T38 pt TCP   : %s\n", ast_test_flag(&peer->flags[1], SIP_PAGE2_T38SUPPORT_TCP)?"Yes":"No");
                ast_cli(fd, "  CanReinvite  : %s\n", ast_test_flag(&peer->flags[0], SIP_CAN_REINVITE)?"Yes":"No");
                ast_cli(fd, "  PromiscRedir : %s\n", ast_test_flag(&peer->flags[0], SIP_PROMISCREDIR)?"Yes":"No");
                ast_cli(fd, "  User=Phone   : %s\n", ast_test_flag(&peer->flags[0], SIP_USEREQPHONE)?"Yes":"No");
@@ -9324,6 +9863,9 @@ static int sip_show_settings(int fd, int argc, char *argv[])
        ast_cli(fd, "  IP ToS SIP:             %s\n", ast_tos2str(global_tos_sip));
        ast_cli(fd, "  IP ToS RTP audio:       %s\n", ast_tos2str(global_tos_audio));
        ast_cli(fd, "  IP ToS RTP video:       %s\n", ast_tos2str(global_tos_video));
+       ast_cli(fd, "  T38 fax pt UDPTL:       %s\n", ast_test_flag(&global_flags[1], SIP_PAGE2_T38SUPPORT_UDPTL) ? "Yes" : "No");
+       ast_cli(fd, "  T38 fax pt RTP:         %s\n", ast_test_flag(&global_flags[1], SIP_PAGE2_T38SUPPORT_RTP) ? "Yes" : "No");
+       ast_cli(fd, "  T38 fax pt TCP:         %s\n", ast_test_flag(&global_flags[1], SIP_PAGE2_T38SUPPORT_TCP) ? "Yes" : "No");
        if (!realtimepeers && !realtimeusers)
                ast_cli(fd, "  SIP realtime:           Disabled\n" );
        else
@@ -10476,6 +11018,11 @@ static int function_sipchaninfo_read(struct ast_channel *chan, char *cmd, char *
                ast_copy_string(buf, p->useragent, len);
        } else  if (!strcasecmp(data, "peername")) {
                ast_copy_string(buf, p->peername, len);
+       } else if (!strcasecmp(data, "t38passthrough")) {
+               if (p->t38.state == T38_DISABLED)
+                       ast_copy_string(buf, "0", sizeof("0"));
+               else    /* T38 is offered or enabled in this call */
+                       ast_copy_string(buf, "1", sizeof("1"));
        } else {
                ast_channel_unlock(chan);
                return -1;
@@ -10498,6 +11045,7 @@ static struct ast_custom_function sipchaninfo_function = {
        "- uri                   The URI from the Contact: header.\n"
        "- useragent             The useragent.\n"
        "- peername              The name of the peer.\n"
+       "- t38passthrough        1 if T38 is offered or enabled in this channel, otherwise 0\n"
 };
 
 /*! \brief Parse 302 Moved temporalily response */
@@ -10672,6 +11220,51 @@ static void handle_response_invite(struct sip_pvt *p, int resp, char *rest, stru
                        build_route(p, req, 1);
                }
                
+               if (p->owner && (p->owner->_state == AST_STATE_UP)) { /* if this is a re-invite */
+                       struct ast_channel *bridgepeer = NULL;
+                       struct sip_pvt *bridgepvt = NULL;
+
+                       bridgepeer = ast_bridged_channel(p->owner);
+                       if (!bridgepeer->tech) {
+                               ast_log(LOG_WARNING, "Ooooh.. no tech!  That's REALLY bad\n");
+                               break;
+                       }
+                       if (!strcasecmp(bridgepeer->tech->type,"SIP")) {
+                               bridgepvt = (struct sip_pvt*)(bridgepeer->tech_pvt);
+                               if (bridgepvt->udptl) {
+                                       if (p->t38.state == T38_PEER_REINVITE) {
+                                               sip_handle_t38_reinvite(bridgepeer, p, 0);
+                                       } else if (p->t38.state == T38_DISABLED && bridgepeer && (bridgepvt->t38.state == T38_ENABLED)) {
+                                               ast_log(LOG_WARNING, "RTP re-inivte after T38 session not handled yet !\n");
+                                               /* Insted of this we should somehow re-invite the other side of the bridge to RTP */
+                                               ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);
+                                       }
+                               } else {
+                                       ast_log(LOG_WARNING, "Strange... The other side of the bridge don't have udptl struct\n");
+                                       ast_mutex_lock(&bridgepvt->lock);
+                                       bridgepvt->t38.state = T38_DISABLED;
+                                       ast_mutex_unlock(&bridgepvt->lock);
+                                       if (option_debug)
+                                               ast_log(LOG_DEBUG,"T38 state changed to %d on channel %s\n", bridgepvt->t38.state, bridgepeer->tech->type);
+                                       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>");
+                               }
+                       } else {
+                               /* Other side is not a SIP channel */
+                               ast_log(LOG_WARNING, "Strange... The other side of the bridge is not a SIP channel\n");
+                               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>");
+                       }
+               }
+               if ((p->t38.state == T38_LOCAL_REINVITE) || (p->t38.state == T38_LOCAL_DIRECT)) {
+                       /* If there was T38 reinvite and we are supposed to answer with 200 OK than this should set us to T38 negotiated mode */
+                       p->t38.state = T38_ENABLED;
+                       if (option_debug)
+                               ast_log(LOG_DEBUG, "T38 changed state to %d on channel %s\n", p->t38.state, p->owner ? p->owner->name : "<none>");
+               }
+
                if (!ast_test_flag(req, SIP_PKT_IGNORE) && p->owner) {
                        if (!reinvite) {
                                ast_queue_control(p->owner, AST_CONTROL_ANSWER);
@@ -11164,6 +11757,10 @@ static void handle_response(struct sip_pvt *p, int resp, char *rest, struct sip_
                                        /* Immediately stop VRTP */
                                        ast_rtp_stop(p->vrtp);
                                }
+                               if (p->udptl) {
+                                       /* Immediately stop UDPTL */
+                                       ast_udptl_stop(p->udptl);
+                               }
                                /* XXX Locking issues?? XXX */
                                switch(resp) {
                                case 300: /* Multiple Choices */
@@ -12280,8 +12877,74 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int
                case AST_STATE_UP:
                        if (option_debug > 1)
                                ast_log(LOG_DEBUG, "%s: New call is UP.... \n", c->name);
-                       transmit_response_with_sdp(p, "200 OK", req, XMIT_CRITICAL);
-
+                       if (p->t38.state == T38_PEER_REINVITE) {
+                               struct ast_channel *bridgepeer = NULL;
+                               struct sip_pvt *bridgepvt = NULL;
+                               
+                               if ((bridgepeer = ast_bridged_channel(p->owner))) {
+                                       /* We have a bridge, and this is re-invite to switchover to T38 so we send re-invite with T38 SDP, to other side of bridge*/
+                                       /*! XXX: we should also check here does the other side supports t38 at all !!! XXX */
+                                       if (!strcasecmp(bridgepeer->tech->type, "SIP")) { /* If we are bridged to SIP channel */
+                                               bridgepvt = (struct sip_pvt*)bridgepeer->tech_pvt;
+                                               if (bridgepvt->t38.state == T38_DISABLED) {
+                                                       if (bridgepvt->udptl) { /* If everything is OK with other side's udptl struct */
+                                                               /* Send re-invite to the bridged channel */
+                                                               sip_handle_t38_reinvite(bridgepeer, p, 1);
+                                                       } else { /* Something is wrong with peers udptl struct */
+                                                               ast_log(LOG_WARNING, "Strange... The other side of the bridge don't have udptl struct\n");
+                                                               ast_mutex_lock(&bridgepvt->lock);
+                                                               bridgepvt->t38.state = T38_DISABLED;
+                                                               ast_mutex_unlock(&bridgepvt->lock);
+                                                               if (option_debug > 1)
+                                                                       ast_log(LOG_DEBUG,"T38 state changed to %d on channel %s\n", bridgepvt->t38.state, bridgepeer->name);
+                                                               if (ast_test_flag(req, SIP_PKT_IGNORE))
+                                                                       transmit_response(p, "488 Not acceptable here", req);
+                                                               else
+                                                                       transmit_response_reliable(p, "488 Not acceptable here", req);
+                                                               ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);
+                                                       }
+                                               }
+                                       } else {
+                                               /* Other side is not a SIP channel */
+                                               if (ast_test_flag(req, SIP_PKT_IGNORE))
+                                                       transmit_response(p, "488 Not acceptable here", req);
+                                               else
+                                                       transmit_response_reliable(p, "488 Not acceptable here", req);
+                                               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>");
+                                               ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);
+                                       }
+                               } else {
+                                       /* we are not bridged in a call */
+                                       transmit_response_with_t38_sdp(p, "200 OK", req, XMIT_CRITICAL);
+                                       p->t38.state = T38_ENABLED;
+                                       if (option_debug)
+                                               ast_log(LOG_DEBUG,"T38 state changed to %d on channel %s\n", p->t38.state, p->owner ? p->owner->name : "<none>");
+                               }
+                       } else if (p->t38.state == T38_DISABLED) { /* Channel doesn't have T38 offered or enabled */
+                               /* If we are bridged to a channel that has T38 enabled than this is a case of RTP re-invite after T38 session */
+                               /* so handle it here (re-invite other party to RTP) */
+                               struct ast_channel *bridgepeer = NULL;
+                               struct sip_pvt *bridgepvt = NULL;
+                               if ((bridgepeer = ast_bridged_channel(p->owner))) {
+                                       if (!strcasecmp(bridgepeer->tech->type, sip_tech.type)) {
+                                               bridgepvt = (struct sip_pvt*)bridgepeer->tech_pvt;
+                                               if (bridgepvt->t38.state == T38_ENABLED) {
+                                                       ast_log(LOG_WARNING, "RTP re-invite after T38 session not handled yet !\n");
+                                                       /* Insted of this we should somehow re-invite the other side of the bridge to RTP */
+                                                       if (ast_test_flag(req, SIP_PKT_IGNORE))
+                                                               transmit_response(p, "488 Not Acceptable Here (unsupported)", req);
+                                                       else
+                                                               transmit_response_reliable(p, "488 Not Acceptable Here (unsupported)", req);
+                                                       ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);
+                                               } else {
+                                                       /* No bridged peer with T38 enabled*/
+                                                       transmit_response_with_sdp(p, "200 OK", req, XMIT_CRITICAL);
+                                               }
+                                       }
+                               }
+                       }
                        break;
                default:
                        ast_log(LOG_WARNING, "Don't know how to handle INVITE in state %d\n", c->_state);
@@ -12780,6 +13443,10 @@ static int handle_request_cancel(struct sip_pvt *p, struct sip_request *req)
                /* Immediately stop VRTP */
                ast_rtp_stop(p->vrtp);
        }
+       if (p->udptl) {
+               /* Immediately stop UDPTL */
+               ast_udptl_stop(p->udptl);
+       }
        if (p->owner)
                ast_queue_hangup(p->owner);
        else
@@ -12835,6 +13502,10 @@ static int handle_request_bye(struct sip_pvt *p, struct sip_request *req)
                /* Immediately stop VRTP */
                ast_rtp_stop(p->vrtp);
        }
+       if (p->udptl) {
+               /* Immediately stop UDPTL */
+               ast_udptl_stop(p->udptl);
+       }
        if (!ast_strlen_zero(get_header(req, "Also"))) {
                ast_log(LOG_NOTICE, "Client '%s' using deprecated BYE/Also transfer method.  Ask vendor to support REFER instead\n",
                        ast_inet_ntoa(iabuf, sizeof(iabuf), p->recv.sin_addr));
@@ -14063,6 +14734,15 @@ static int handle_common_options(struct ast_flags *flags, struct ast_flags *mask
        } else if (!strcasecmp(v->name, "allowsubscribe")) {
                ast_set_flag(&mask[1], SIP_PAGE2_ALLOWSUBSCRIBE);
                ast_set2_flag(&flags[1], ast_true(v->value), SIP_PAGE2_ALLOWSUBSCRIBE);
+       } else if (!strcasecmp(v->name, "t38pt_udptl")) {
+               ast_set_flag(&mask[1], SIP_PAGE2_T38SUPPORT_UDPTL);
+               ast_set2_flag(&flags[1], ast_true(v->value), SIP_PAGE2_T38SUPPORT_UDPTL);
+       } else if (!strcasecmp(v->name, "t38pt_rtp")) {
+               ast_set_flag(&mask[1], SIP_PAGE2_T38SUPPORT_RTP);
+               ast_set2_flag(&flags[1], ast_true(v->value), SIP_PAGE2_T38SUPPORT_RTP);
+       } else if (!strcasecmp(v->name, "t38pt_tcp")) {
+               ast_set_flag(&mask[1], SIP_PAGE2_T38SUPPORT_TCP);
+               ast_set2_flag(&flags[1], ast_true(v->value), SIP_PAGE2_T38SUPPORT_TCP);
        }
 
        return res;
@@ -14309,7 +14989,22 @@ static struct sip_user *build_user(const char *name, struct ast_variable *v, int
                        user->maxcallbitrate = atoi(v->value);
                        if (user->maxcallbitrate < 0)
                                user->maxcallbitrate = default_maxcallbitrate;
-               }
+               } else if (!strcasecmp(v->name, "t38pt_udptl")) {
+                       if (ast_true(v->value)) {
+                               ast_set_flag(&user->flags[1], SIP_PAGE2_T38SUPPORT_UDPTL);
+                       } else
+                               ast_clear_flag(&user->flags[1], SIP_PAGE2_T38SUPPORT_UDPTL);
+               } else if (!strcasecmp(v->name, "t38pt_rtp")) {
+                       if (ast_true(v->value)) {
+                               ast_set_flag(&user->flags[1], SIP_PAGE2_T38SUPPORT_RTP);
+                       } else
+                               ast_clear_flag(&user->flags[1], SIP_PAGE2_T38SUPPORT_RTP);
+               } else if (!strcasecmp(v->name, "t38pt_tcp")) {
+                       if (ast_true(v->value)) {
+                               ast_set_flag(&user->flags[1], SIP_PAGE2_T38SUPPORT_TCP);
+                       } else
+                               ast_clear_flag(&user->flags[1], SIP_PAGE2_T38SUPPORT_TCP);
+               }
        }
        ast_copy_flags(&user->flags[0], &userflags[0], mask[0].flags);
        ast_copy_flags(&user->flags[1], &userflags[1], mask[1].flags);
@@ -14591,6 +15286,21 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, int
                        peer->maxcallbitrate = atoi(v->value);
                        if (peer->maxcallbitrate < 0)
                                peer->maxcallbitrate = default_maxcallbitrate;
+               } else if (!strcasecmp(v->name, "t38pt_udptl")) {
+                       if (ast_true(v->value)) {
+                               ast_set_flag(&peer->flags[1], SIP_PAGE2_T38SUPPORT_UDPTL);
+                       } else
+                               ast_clear_flag(&peer->flags[1], SIP_PAGE2_T38SUPPORT_UDPTL);
+               } else if (!strcasecmp(v->name, "t38pt_rtp")) {
+                       if (ast_true(v->value)) {
+                               ast_set_flag(&peer->flags[1], SIP_PAGE2_T38SUPPORT_RTP);
+                       } else
+                               ast_clear_flag(&peer->flags[1], SIP_PAGE2_T38SUPPORT_RTP);
+               } else if (!strcasecmp(v->name, "t38pt_tcp")) {
+                       if (ast_true(v->value)) {
+                               ast_set_flag(&peer->flags[1], SIP_PAGE2_T38SUPPORT_TCP);
+                       } else
+                               ast_clear_flag(&peer->flags[1], SIP_PAGE2_T38SUPPORT_TCP);
                }
        }
        if (!ast_test_flag(&global_flags[1], SIP_PAGE2_IGNOREREGEXPIRE) && ast_test_flag(&peer->flags[1], SIP_PAGE2_DYNAMIC) && realtime) {
@@ -14952,6 +15662,18 @@ static int reload_config(enum channelreloadreason reason)
                        default_maxcallbitrate = atoi(v->value);
                        if (default_maxcallbitrate < 0)
                                default_maxcallbitrate = DEFAULT_MAX_CALL_BITRATE;
+               } else if (!strcasecmp(v->name, "t38pt_udptl")) {
+                       if (ast_true(v->value)) {
+                               ast_set_flag(&global_flags[1], SIP_PAGE2_T38SUPPORT_UDPTL);
+                       }
+               } else if (!strcasecmp(v->name, "t38pt_rtp")) {
+                       if (ast_true(v->value)) {
+                               ast_set_flag(&global_flags[1], SIP_PAGE2_T38SUPPORT_RTP);
+                       }
+               } else if (!strcasecmp(v->name, "t38pt_tcp")) {
+                       if (ast_true(v->value)) {
+                               ast_set_flag(&global_flags[1], SIP_PAGE2_T38SUPPORT_TCP);
+                       }
                }
        }
 
@@ -15093,6 +15815,131 @@ static int reload_config(enum channelreloadreason reason)
        return 0;
 }
 
+static struct ast_udptl *sip_get_udptl_peer(struct ast_channel *chan)
+{
+       struct sip_pvt *p;
+       struct ast_udptl *udptl = NULL;
+       
+       p = chan->tech_pvt;
+       if (!p)
+               return NULL;
+       
+       ast_mutex_lock(&p->lock);
+       if (p->udptl && ast_test_flag(&p->flags[0], SIP_CAN_REINVITE))
+               udptl = p->udptl;
+       ast_mutex_unlock(&p->lock);
+       return udptl;
+}
+
+static int sip_set_udptl_peer(struct ast_channel *chan, struct ast_udptl *udptl)
+{
+       struct sip_pvt *p;
+       
+       p = chan->tech_pvt;
+       if (!p)
+               return -1;
+       ast_mutex_lock(&p->lock);
+       if (udptl)
+               ast_udptl_get_peer(udptl, &p->udptlredirip);
+       else
+               memset(&p->udptlredirip, 0, sizeof(p->udptlredirip));
+       if (!ast_test_flag(&p->flags[0], SIP_GOTREFER)) {
+               if (!p->pendinginvite) {
+                       if (option_debug > 2) {
+                               char iabuf[INET_ADDRSTRLEN];
+                               ast_log(LOG_DEBUG, "Sending reinvite on SIP '%s' - It's UDPTL soon redirected to IP %s:%d\n", p->callid, ast_inet_ntoa(iabuf, sizeof(iabuf), udptl ? p->udptlredirip.sin_addr : p->ourip), udptl ? ntohs(p->udptlredirip.sin_port) : 0);
+                       }
+                       transmit_reinvite_with_t38_sdp(p);
+               } else if (!ast_test_flag(&p->flags[0], SIP_PENDINGBYE)) {
+                       if (option_debug > 2) {
+                               char iabuf[INET_ADDRSTRLEN];
+                               ast_log(LOG_DEBUG, "Deferring reinvite on SIP '%s' - It's UDPTL will be redirected to IP %s:%d\n", p->callid, ast_inet_ntoa(iabuf, sizeof(iabuf),udptl ? p->udptlredirip.sin_addr : p->ourip), udptl ? ntohs(p->udptlredirip.sin_port) : 0);
+                       }
+                       ast_set_flag(&p->flags[0], SIP_NEEDREINVITE);
+               }
+       }
+       /* Reset lastrtprx timer */
+       p->lastrtprx = p->lastrtptx = time(NULL);
+       ast_mutex_unlock(&p->lock);
+       return 0;
+}
+
+static int sip_handle_t38_reinvite(struct ast_channel *chan, struct sip_pvt *pvt, int reinvite)
+{
+       struct sip_pvt *p;
+       int flag = 0;
+       
+       p = chan->tech_pvt;
+       if (!p || !pvt->udptl)
+               return -1;
+       
+       /* Setup everything on the other side like offered/responded from first side */
+       ast_mutex_lock(&p->lock);
+       p->t38.jointcapability = p->t38.peercapability = pvt->t38.jointcapability;
+       ast_udptl_set_far_max_datagram(p->udptl, ast_udptl_get_local_max_datagram(pvt->udptl));
+       ast_udptl_set_local_max_datagram(p->udptl, ast_udptl_get_local_max_datagram(pvt->udptl));
+       ast_udptl_set_error_correction_scheme(p->udptl, ast_udptl_get_error_correction_scheme(pvt->udptl));
+       
+       if (reinvite) {         /* If we are handling sending re-invite to the other side of the bridge */
+               if (ast_test_flag(&p->flags[0], SIP_CAN_REINVITE) && ast_test_flag(&pvt->flags[0], SIP_CAN_REINVITE)) {
+                       ast_udptl_get_peer(pvt->udptl, &p->udptlredirip);
+                       flag =1;
+               } else {
+                       memset(&p->udptlredirip, 0, sizeof(p->udptlredirip));
+               }
+               if (!ast_test_flag(&p->flags[0], SIP_GOTREFER)) {
+                       if (!p->pendinginvite) {
+                               if (option_debug > 2) {
+                                       char iabuf[INET_ADDRSTRLEN];
+                                       if (flag)
+                                               ast_log(LOG_DEBUG, "Sending reinvite on SIP '%s' - It's UDPTL soon redirected to IP %s:%d\n", p->callid, ast_inet_ntoa(iabuf, sizeof(iabuf), p->udptlredirip.sin_addr), ntohs(p->udptlredirip.sin_port));
+                                       else
+                                               ast_log(LOG_DEBUG, "Sending reinvite on SIP '%s' - It's UDPTL soon redirected to us (IP %s)\n", p->callid, ast_inet_ntoa(iabuf, sizeof(iabuf), p->ourip));
+                               }
+                               transmit_reinvite_with_t38_sdp(p);
+                       } else if (!ast_test_flag(&p->flags[0], SIP_PENDINGBYE)) {
+                               if (option_debug > 2) {
+                                       char iabuf[INET_ADDRSTRLEN];
+                                       if (flag)
+                                               ast_log(LOG_DEBUG, "Deferring reinvite on SIP '%s' - It's UDPTL will be redirected to IP %s:%d\n", p->callid, ast_inet_ntoa(iabuf, sizeof(iabuf), p->udptlredirip.sin_addr), ntohs(p->udptlredirip.sin_port));
+                                       else
+                                               ast_log(LOG_DEBUG, "Deferring reinvite on SIP '%s' - It's UDPTL will be redirected to us (IP %s)\n", p->callid, ast_inet_ntoa(iabuf, sizeof(iabuf), p->ourip));
+                               }
+                               ast_set_flag(&p->flags[0], SIP_NEEDREINVITE);
+                       }
+               }
+               /* Reset lastrtprx timer */
+               p->lastrtprx = p->lastrtptx = time(NULL);
+               ast_mutex_unlock(&p->lock);
+               return 0;
+       } else {        /* If we are handling sending 200 OK to the other side of the bridge */
+               if (ast_test_flag(&p->flags[0], SIP_CAN_REINVITE) && ast_test_flag(&pvt->flags[0], SIP_CAN_REINVITE)) {
+                       ast_udptl_get_peer(pvt->udptl, &p->udptlredirip);
+                       flag = 1;
+               } else {
+                       memset(&p->udptlredirip, 0, sizeof(p->udptlredirip));
+               }
+               if (option_debug > 2) {
+                       char iabuf[INET_ADDRSTRLEN];
+                       if (flag)
+                               ast_log(LOG_DEBUG, "Responding 200 OK on SIP '%s' - It's UDPTL soon redirected to IP %s:%d\n", p->callid, ast_inet_ntoa(iabuf, sizeof(iabuf), p->udptlredirip.sin_addr), ntohs(p->udptlredirip.sin_port));
+                       else
+                               ast_log(LOG_DEBUG, "Responding 200 OK on SIP '%s' - It's UDPTL soon redirected to us (IP %s)\n", p->callid, ast_inet_ntoa(iabuf, sizeof(iabuf), p->ourip));
+               }
+               pvt->t38.state = T38_ENABLED;
+               p->t38.state = T38_ENABLED;
+               if (option_debug > 1) {
+                       ast_log(LOG_DEBUG, "T38 changed state to %d on channel %s\n", pvt->t38.state, pvt->owner ? pvt->owner->name : "<none>");
+                       ast_log(LOG_DEBUG, "T38 changed state to %d on channel %s\n", p->t38.state, chan ? chan->name : "<none>");
+               }
+               transmit_response_with_t38_sdp(p, "200 OK", &p->initreq, XMIT_CRITICAL);
+               p->lastrtprx = p->lastrtptx = time(NULL);
+               ast_mutex_unlock(&p->lock);
+               return 0;
+       }
+}
+
+
 /*! \brief Returns null if we can't reinvite audio (part of RTP interface) */
 static struct ast_rtp *sip_get_rtp_peer(struct ast_channel *chan)
 {
@@ -15522,6 +16369,9 @@ static int load_module(void *mod)
        /* Tell the RTP subdriver that we're here */
        ast_rtp_proto_register(&sip_rtp);
 
+       /* Tell the UDPTL subdriver that we're here */
+       ast_udptl_proto_register(&sip_udptl);
+
        /* Register dialplan applications */
        ast_register_application(app_dtmfmode, sip_dtmfmode, synopsis_dtmfmode, descrip_dtmfmode);
        ast_register_application(app_sipaddheader, sip_addheader, synopsis_sipaddheader, descrip_sipaddheader);
@@ -15566,6 +16416,8 @@ static int unload_module(void *mod)
 
        ast_rtp_proto_unregister(&sip_rtp);
 
+       ast_udptl_proto_unregister(&sip_udptl);
+
        ast_manager_unregister("SIPpeers");
        ast_manager_unregister("SIPshowpeer");