diff --git a/UPGRADE.txt b/UPGRADE.txt index 1c41d90fed98c5ce5d7a58987ccdc0d6fadc8e76..61d4ec148c85d874d92ef68ddf644e304c438c31 100644 --- a/UPGRADE.txt +++ b/UPGRADE.txt @@ -67,6 +67,14 @@ From 1.6.1 to 1.6.2: instead, it is configured on a per-peer (or global) basis in sip.conf, with the same default as was present in udptl.conf.sample. +* T.38 FAX maximum datagram size can no longer be configured in updtl.conf; + instead, it is either supplied by the application servicing the T.38 channel + (for a FAX send or receive) or calculated from the bridged endpoint's + maximum datagram size (for a T.38 FAX passthrough call). In addition, sip.conf + allows for overriding the value supplied by a remote endpoint, which is useful + when T.38 connections are made to gateways that supply incorrectly-calculated + maximum datagram sizes. + * There have been some changes to the IAX2 protocol to address the security concerns documented in the security advisory AST-2009-006. Please see the IAX2 security document, doc/IAX2-security.pdf, for information regarding diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 7f8b3c039b3cc7021ea63abcc0737cf38c41c4b8..4bfe696dabb31c0e63db9b730e16b6b6933c19b5 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -1272,6 +1272,8 @@ static int regobjs = 0; /*!< Registry objects */ /* }@ */ static struct ast_flags global_flags[2] = {{0}}; /*!< global SIP_ flags */ +static int global_t38_maxdatagram; /*!< global T.38 FaxMaxDatagram override */ + static char used_context[AST_MAX_CONTEXT]; /*!< name of automatically created context for unloading */ @@ -1518,10 +1520,10 @@ struct sip_auth { #define SIP_PAGE2_SUBSCRIBEMWIONLY (1 << 18) /*!< GP: Only issue MWI notification if subscribed to */ #define SIP_PAGE2_IGNORESDPVERSION (1 << 19) /*!< GDP: Ignore the SDP session version number we receive and treat all sessions as new */ -#define SIP_PAGE2_T38SUPPORT (7 << 20) /*!< GDP: T.38 Fax Support */ +#define SIP_PAGE2_T38SUPPORT (3 << 20) /*!< GDP: T.38 Fax Support */ #define SIP_PAGE2_T38SUPPORT_UDPTL (1 << 20) /*!< GDP: T.38 Fax Support (no error correction) */ #define SIP_PAGE2_T38SUPPORT_UDPTL_FEC (2 << 20) /*!< GDP: T.38 Fax Support (FEC error correction) */ -#define SIP_PAGE2_T38SUPPORT_UDPTL_REDUNDANCY (4 << 20) /*!< GDP: T.38 Fax Support (redundancy error correction) */ +#define SIP_PAGE2_T38SUPPORT_UDPTL_REDUNDANCY (3 << 20) /*!< GDP: T.38 Fax Support (redundancy error correction) */ #define SIP_PAGE2_CALL_ONHOLD (3 << 23) /*!< D: Call hold states: */ #define SIP_PAGE2_CALL_ONHOLD_ACTIVE (1 << 23) /*!< D: Active hold */ @@ -1761,6 +1763,7 @@ struct sip_pvt { int jointnoncodeccapability; /*!< Joint Non codec capability */ int redircodecs; /*!< Redirect codecs */ int maxcallbitrate; /*!< Maximum Call Bitrate for Video Calls */ + int t38_maxdatagram; /*!< T.38 FaxMaxDatagram override */ int request_queue_sched_id; /*!< Scheduler ID of any scheduled action to process queued requests */ int provisional_keepalive_sched_id; /*!< Scheduler ID for provisional responses that need to be sent out to avoid cancellation */ const char *last_provisional; /*!< The last successfully transmitted provisonal response message */ @@ -2009,6 +2012,7 @@ struct sip_peer { int inRinging; /*!< Number of calls ringing */ int onHold; /*!< Peer has someone on hold */ int call_limit; /*!< Limit of concurrent calls */ + int t38_maxdatagram; /*!< T.38 FaxMaxDatagram override */ int busy_level; /*!< Level of active channels where we signal busy */ enum transfermodes allowtransfer; /*! SIP Refer restriction scheme */ struct ast_codec_pref prefs; /*!< codec prefs */ @@ -5178,6 +5182,7 @@ static int create_addr_from_peer(struct sip_pvt *dialog, struct sip_peer *peer) /* t38pt_udptl was enabled in the peer and not in [general] */ dialog->udptl = ast_udptl_new_with_bindaddr(sched, io, 0, bindaddr.sin_addr); } + dialog->t38_maxdatagram = peer->t38_maxdatagram; set_t38_capabilities(dialog); } else if (dialog->udptl) { ast_udptl_destroy(dialog->udptl); @@ -7235,6 +7240,7 @@ static struct sip_pvt *sip_alloc(ast_string_field callid, struct sockaddr_in *si if (sip_methods[intended_method].need_rtp) { if (ast_test_flag(&p->flags[1], SIP_PAGE2_T38SUPPORT) && (p->udptl = ast_udptl_new_with_bindaddr(sched, io, 0, bindaddr.sin_addr))) { ast_udptl_setqos(p->udptl, global_tos_audio, global_cos_audio); + p->t38_maxdatagram = global_t38_maxdatagram; } p->maxcallbitrate = default_maxcallbitrate; p->autoframing = global_autoframing; @@ -7263,6 +7269,7 @@ static struct sip_pvt *sip_alloc(ast_string_field callid, struct sockaddr_in *si (ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_AUTO)) p->noncodeccapability |= AST_RTP_DTMF; if (p->udptl) { + p->t38_maxdatagram = global_t38_maxdatagram; set_t38_capabilities(p); } ast_string_field_set(p, context, sip_cfg.default_context); @@ -8725,6 +8732,11 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action ast_debug(3, "FaxVersion: %d\n", x); p->t38.their_parms.version = x; } else if ((sscanf(a, "T38FaxMaxDatagram:%30d", &x) == 1) || (sscanf(a, "T38MaxDatagram:%30d", &x) == 1)) { + /* override the supplied value if the configuration requests it */ + if (p->t38_maxdatagram > x) { + ast_debug(1, "Overriding T38FaxMaxDatagram '%d' with '%d'\n", x, p->t38_maxdatagram); + x = p->t38_maxdatagram; + } found = 1; ast_debug(3, "FaxMaxDatagram: %d\n", x); ast_udptl_set_far_max_datagram(p->udptl, x); @@ -14262,6 +14274,7 @@ static enum check_auth_result check_peer_ok(struct sip_pvt *p, char *of, ast_copy_flags(&p->flags[1], &peer->flags[1], SIP_PAGE2_FLAGS_TO_COPY); if (ast_test_flag(&p->flags[1], SIP_PAGE2_T38SUPPORT) && p->udptl) { + p->t38_maxdatagram = peer->t38_maxdatagram; set_t38_capabilities(p); } @@ -15577,6 +15590,18 @@ static void peer_mailboxes_to_str(struct ast_str **mailbox_str, struct sip_peer } } +static struct _map_x_s faxecmodes[] = { + { SIP_PAGE2_T38SUPPORT_UDPTL, "None"}, + { SIP_PAGE2_T38SUPPORT_UDPTL_FEC, "FEC"}, + { SIP_PAGE2_T38SUPPORT_UDPTL_REDUNDANCY, "Redundancy"}, + { -1, NULL}, +}; + +static const char *faxec2str(int faxec) +{ + return map_x_s(faxecmodes, faxec, "Unknown"); +} + /*! \brief Show one peer in detail (main function) */ static char *_sip_show_peer(int type, int fd, struct mansession *s, const struct message *m, int argc, const char *argv[]) { @@ -15655,7 +15680,9 @@ static char *_sip_show_peer(int type, int fd, struct mansession *s, const struct ast_cli(fd, " Insecure : %s\n", insecure2str(ast_test_flag(&peer->flags[0], SIP_INSECURE))); ast_cli(fd, " Force rport : %s\n", cli_yesno(ast_test_flag(&peer->flags[0], SIP_NAT_FORCE_RPORT))); ast_cli(fd, " ACL : %s\n", cli_yesno(peer->ha != NULL)); - ast_cli(fd, " T38 pt UDPTL : %s\n", cli_yesno(ast_test_flag(&peer->flags[1], SIP_PAGE2_T38SUPPORT))); + ast_cli(fd, " T.38 support : %s\n", cli_yesno(ast_test_flag(&peer->flags[1], SIP_PAGE2_T38SUPPORT))); + ast_cli(fd, " T.38 EC mode : %s\n", faxec2str(ast_test_flag(&peer->flags[1], SIP_PAGE2_T38SUPPORT))); + ast_cli(fd, " T.38 MaxDtgrm: %d\n", peer->t38_maxdatagram); ast_cli(fd, " DirectMedia : %s\n", cli_yesno(ast_test_flag(&peer->flags[0], SIP_DIRECT_MEDIA))); ast_cli(fd, " PromiscRedir : %s\n", cli_yesno(ast_test_flag(&peer->flags[0], SIP_PROMISCREDIR))); ast_cli(fd, " User=Phone : %s\n", cli_yesno(ast_test_flag(&peer->flags[0], SIP_USEREQPHONE))); @@ -15767,6 +15794,9 @@ static char *_sip_show_peer(int type, int fd, struct mansession *s, const struct astman_append(s, "SIP-UserPhone: %s\r\n", (ast_test_flag(&peer->flags[0], SIP_USEREQPHONE)?"Y":"N")); astman_append(s, "SIP-VideoSupport: %s\r\n", (ast_test_flag(&peer->flags[1], SIP_PAGE2_VIDEOSUPPORT)?"Y":"N")); astman_append(s, "SIP-TextSupport: %s\r\n", (ast_test_flag(&peer->flags[1], SIP_PAGE2_TEXTSUPPORT)?"Y":"N")); + astman_append(s, "SIP-T.38Support: %s\r\n", (ast_test_flag(&peer->flags[1], SIP_PAGE2_T38SUPPORT)?"Y":"N")); + astman_append(s, "SIP-T.38EC: %s\r\n", faxec2str(ast_test_flag(&peer->flags[1], SIP_PAGE2_T38SUPPORT))); + astman_append(s, "SIP-T.38MaxDtgrm: %d\r\n", peer->t38_maxdatagram); astman_append(s, "SIP-Sess-Timers: %s\r\n", stmode2str(peer->stimer.st_mode_oper)); astman_append(s, "SIP-Sess-Refresh: %s\r\n", strefresher2str(peer->stimer.st_ref)); astman_append(s, "SIP-Sess-Expires: %d\r\n", peer->stimer.st_max_se); @@ -16215,7 +16245,9 @@ static char *sip_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_ ast_cli(a->fd, " Call Events: %s\n", sip_cfg.callevents ? "On" : "Off"); ast_cli(a->fd, " Auth. Failure Events: %s\n", global_authfailureevents ? "On" : "Off"); - ast_cli(a->fd, " T38 fax pt UDPTL: %s\n", cli_yesno(ast_test_flag(&global_flags[1], SIP_PAGE2_T38SUPPORT))); + ast_cli(a->fd, " T.38 support: %s\n", cli_yesno(ast_test_flag(&global_flags[1], SIP_PAGE2_T38SUPPORT))); + ast_cli(a->fd, " T.38 EC mode: %s\n", faxec2str(ast_test_flag(&global_flags[1], SIP_PAGE2_T38SUPPORT))); + ast_cli(a->fd, " T.38 MaxDtgrm: %d\n", global_t38_maxdatagram); if (!realtimepeers && !realtimeregs) ast_cli(a->fd, " SIP realtime: Disabled\n" ); else @@ -20493,6 +20525,7 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int /* If T38 is needed but not present, then make it magically appear */ if (ast_test_flag(&p->flags[1], SIP_PAGE2_T38SUPPORT) && !p->udptl && (p->udptl = ast_udptl_new_with_bindaddr(sched, io, 0, bindaddr.sin_addr))) { + p->t38_maxdatagram = global_t38_maxdatagram; set_t38_capabilities(p); } @@ -23725,6 +23758,48 @@ static void set_insecure_flags (struct ast_flags *flags, const char *value, int } } +/*! + \brief Handle T.38 configuration options common to users and peers + \returns non-zero if any config options were handled, zero otherwise +*/ +static int handle_t38_options(struct ast_flags *flags, struct ast_flags *mask, struct ast_variable *v, + int *maxdatagram) +{ + int res = 1; + + if (!strcasecmp(v->name, "t38pt_udptl")) { + char *buf = ast_strdupa(v->value); + char *word, *next = buf; + + ast_set_flag(&mask[1], SIP_PAGE2_T38SUPPORT); + + while ((word = strsep(&next, ","))) { + if (ast_true(word) || !strcasecmp(word, "fec")) { + ast_clear_flag(&flags[1], SIP_PAGE2_T38SUPPORT); + ast_set_flag(&flags[1], SIP_PAGE2_T38SUPPORT_UDPTL_FEC); + } else if (!strcasecmp(word, "redundancy")) { + ast_clear_flag(&flags[1], SIP_PAGE2_T38SUPPORT); + ast_set_flag(&flags[1], SIP_PAGE2_T38SUPPORT_UDPTL_REDUNDANCY); + } else if (!strcasecmp(word, "none")) { + ast_clear_flag(&flags[1], SIP_PAGE2_T38SUPPORT); + ast_set_flag(&flags[1], SIP_PAGE2_T38SUPPORT_UDPTL); + } else if (!strncasecmp(word, "maxdatagram=", 12)) { + if (sscanf(&word[12], "%30d", maxdatagram) != 1) { + ast_log(LOG_WARNING, "Invalid maxdatagram '%s' at line %d of %s\n", v->value, v->lineno, config); + *maxdatagram = global_t38_maxdatagram; + } + } + } + } else if (!strcasecmp(v->name, "t38pt_usertpsource")) { + ast_set_flag(&mask[1], SIP_PAGE2_UDPTL_DESTINATION); + ast_set2_flag(&flags[1], ast_true(v->value), SIP_PAGE2_UDPTL_DESTINATION); + } else { + res = 0; + } + + return res; +} + /*! \brief Handle flag-type options common to configuration of devices - peers \param flags array of two struct ast_flags @@ -23851,34 +23926,12 @@ static int handle_common_options(struct ast_flags *flags, struct ast_flags *mask } else if (!strcasecmp(v->name, "faxdetect")) { ast_set_flag(&mask[1], SIP_PAGE2_FAX_DETECT); ast_set2_flag(&flags[1], ast_true(v->value), SIP_PAGE2_FAX_DETECT); - } else if (!strcasecmp(v->name, "t38pt_udptl")) { - char buf[16], *word, *next = buf; - - ast_set_flag(&mask[1], SIP_PAGE2_T38SUPPORT); - - ast_copy_string(buf, v->value, sizeof(buf)); - - while ((word = strsep(&next, ","))) { - if (ast_true(word) || !strcasecmp(word, "fec")) { - ast_clear_flag(&flags[1], SIP_PAGE2_T38SUPPORT); - ast_set_flag(&flags[1], SIP_PAGE2_T38SUPPORT_UDPTL_FEC); - } else if (!strcasecmp(word, "redundancy")) { - ast_clear_flag(&flags[1], SIP_PAGE2_T38SUPPORT); - ast_set_flag(&flags[1], SIP_PAGE2_T38SUPPORT_UDPTL_REDUNDANCY); - } else if (!strcasecmp(word, "none")) { - ast_clear_flag(&flags[1], SIP_PAGE2_T38SUPPORT); - ast_set_flag(&flags[1], SIP_PAGE2_T38SUPPORT_UDPTL); - } - } } else if (!strcasecmp(v->name, "rfc2833compensate")) { ast_set_flag(&mask[1], SIP_PAGE2_RFC2833_COMPENSATE); ast_set2_flag(&flags[1], ast_true(v->value), SIP_PAGE2_RFC2833_COMPENSATE); } else if (!strcasecmp(v->name, "buggymwi")) { ast_set_flag(&mask[1], SIP_PAGE2_BUGGY_MWI); ast_set2_flag(&flags[1], ast_true(v->value), SIP_PAGE2_BUGGY_MWI); - } else if (!strcasecmp(v->name, "t38pt_usertpsource")) { - ast_set_flag(&mask[1], SIP_PAGE2_UDPTL_DESTINATION); - ast_set2_flag(&flags[1], ast_true(v->value), SIP_PAGE2_UDPTL_DESTINATION); } else if (!strcasecmp(v->name, "constantssrc")) { ast_set_flag(&mask[1], SIP_PAGE2_CONSTANT_SSRC); ast_set2_flag(&flags[1], ast_true(v->value), SIP_PAGE2_CONSTANT_SSRC); @@ -24085,6 +24138,7 @@ static void set_peer_defaults(struct sip_peer *peer) peer->rtpkeepalive = global_rtpkeepalive; peer->allowtransfer = sip_cfg.allowtransfer; peer->autoframing = global_autoframing; + peer->t38_maxdatagram = global_t38_maxdatagram; peer->qualifyfreq = global_qualifyfreq; if (global_callcounter) peer->call_limit=INT_MAX; @@ -24244,6 +24298,9 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, str if (handle_common_options(&peerflags[0], &mask[0], v)) { continue; } + if (handle_t38_options(&peerflags[0], &mask[0], v, &peer->t38_maxdatagram)) { + continue; + } if (!strcasecmp(v->name, "transport") && !ast_strlen_zero(v->value)) { char *val = ast_strdupa(v->value); char *trans; @@ -24955,6 +25012,7 @@ static int reload_config(enum channelreloadreason reason) global_timer_b = 64 * DEFAULT_TIMER_T1; global_t1min = DEFAULT_T1MIN; global_qualifyfreq = DEFAULT_QUALIFYFREQ; + global_t38_maxdatagram = -1; sip_cfg.matchexterniplocally = DEFAULT_MATCHEXTERNIPLOCALLY; @@ -24971,6 +25029,9 @@ static int reload_config(enum channelreloadreason reason) for (v = ast_variable_browse(cfg, "general"); v; v = v->next) { if (handle_common_options(&global_flags[0], &dummy[0], v)) continue; + if (handle_t38_options(&global_flags[0], &dummy[0], v, &global_t38_maxdatagram)) { + continue; + } /* handle jb conf */ if (!ast_jb_read_conf(&global_jbconf, v->name, v->value)) continue; diff --git a/configs/sip.conf.sample b/configs/sip.conf.sample index 23c16979cd954ff5244402d8c363937d58d7d49b..f32d60915fbed1aa23580055c130c4631014ee55 100644 --- a/configs/sip.conf.sample +++ b/configs/sip.conf.sample @@ -496,22 +496,32 @@ srvlookup=yes ; Enable DNS SRV lookups on outbound calls ;callcounter = yes ; Enable call counters on devices. This can be set per ; device too. -;----------------------------------------- T.38 FAX PASSTHROUGH SUPPORT ----------------------- +;----------------------------------------- T.38 FAX SUPPORT ---------------------------------- ; ; This setting is available in the [general] section as well as in device configurations. -; Setting this to yes, enables T.38 fax (UDPTL) passthrough on SIP to SIP calls, provided -; both parties have T38 support enabled in their Asterisk configuration -; This has to be enabled in the general section for all devices to work. You can then -; disable it on a per device basis. -; -; T.38 faxing only works in SIP to SIP calls. It defaults to off. +; Setting this to yes enables T.38 FAX (UDPTL) on SIP calls; it defaults to off. ; ; t38pt_udptl = yes ; Enables T.38 with FEC error correction. ; t38pt_udptl = yes,fec ; Enables T.38 with FEC error correction. ; t38pt_udptl = yes,redundancy ; Enables T.38 with redundancy error correction. ; t38pt_udptl = yes,none ; Enables T.38 with no error correction. ; -; Faxs Detect will cause the SIP channel to jump to the 'fax' extension (if it exists) +; In some cases, T.38 endpoints will provide a T38FaxMaxDatagram value (during T.38 setup) that +; is based on an incorrect interpretation of the T.38 recommendation, and results in failures +; because Asterisk does not believe it can send T.38 packets of a reasonable size to that +; endpoint (Cisco media gateways are one example of this situation). In these cases, during a +; T.38 call you will see warning messages on the console/in the logs from the Asterisk UDPTL +; stack complaining about lack of buffer space to send T.38 FAX packets. If this occurs, you +; can set an override (globally, or on a per-device basis) to make Asterisk ignore the +; T38FaxMaxDatagram value specified by the other endpoint, and use a configured value instead. +; This can be done by appending 'maxdatagram=<value>' to the t38pt_udptl configuration option, +; like this: +; +; t38pt_udptl = yes,fec,maxdatagram=400 ; Enables T.38 with FEC error correction and overrides +; ; the other endpoint's provided value to assume we can +; ; send 400 byte T.38 FAX packets to it. +; +; FAX detection will cause the SIP channel to jump to the 'fax' extension (if it exists) ; after T.38 is successfully negotiated. ; ; faxdetect = yes ; Default false diff --git a/configs/udptl.conf.sample b/configs/udptl.conf.sample index 97df84213d7ff501e1ad1530aee6db11f3a72100..1d635da5ca48dbbc77d6e19432045e70c5969ae6 100644 --- a/configs/udptl.conf.sample +++ b/configs/udptl.conf.sample @@ -12,10 +12,6 @@ udptlend=4999 ; ;udptlchecksums=no ; -; The maximum length of a UDPTL packet -; -T38FaxMaxDatagram = 400 -; ; The number of error correction entries in a UDPTL packet ; udptlfecentries = 3 diff --git a/main/udptl.c b/main/udptl.c index edaa3c70ed84ab79ccfe02b790cc55c8b06bdc62..db2ae8f0117c91f5e00bf78c00cc7346685341f3 100644 --- a/main/udptl.c +++ b/main/udptl.c @@ -711,7 +711,7 @@ struct ast_frame *ast_udptl_read(struct ast_udptl *udptl) static void calculate_local_max_datagram(struct ast_udptl *udptl) { - unsigned int new_max = 200; + unsigned int new_max = 0; /* calculate the amount of space required to receive an IFP * using the current error correction mode, and ensure that our @@ -741,32 +741,28 @@ static void calculate_local_max_datagram(struct ast_udptl *udptl) static void calculate_far_max_ifp(struct ast_udptl *udptl) { - unsigned new_max = 60; + unsigned new_max = 0; /* calculate the maximum IFP the local endpoint should * generate based on the far end's maximum datagram size - * and the current error correction mode. some endpoints - * bogus 'max datagram' values that would result in unusable - * (too small) maximum IFP values, so we have a a reasonable - * minimum value to ensure that we can actually construct - * UDPTL packets. + * and the current error correction mode. */ switch (udptl->error_correction_scheme) { case UDPTL_ERROR_CORRECTION_NONE: /* only need room for sequence number and length indicators */ - new_max = MAX(new_max, udptl->far_max_datagram - 6); + new_max = udptl->far_max_datagram - 6; break; case UDPTL_ERROR_CORRECTION_REDUNDANCY: /* need room for sequence number, length indicators and the * configured number of redundant packets */ - new_max = MAX(new_max, (udptl->far_max_datagram - 8) / (udptl->error_correction_entries + 1)); + new_max = (udptl->far_max_datagram - 8) / (udptl->error_correction_entries + 1); break; case UDPTL_ERROR_CORRECTION_FEC: /* need room for sequence number, length indicators and a * a single IFP of the maximum size expected */ - new_max = MAX(new_max, (udptl->far_max_datagram - 10) / 2); + new_max = (udptl->far_max_datagram - 10) / 2; break; } /* subtract 25% of space for insurance */ @@ -998,7 +994,9 @@ int ast_udptl_write(struct ast_udptl *s, struct ast_frame *f) } if (f->datalen > s->far_max_ifp) { - ast_log(LOG_WARNING, "UDPTL asked to send %d bytes of IFP when far end only prepared to accept %d bytes; data loss may occur.\n", f->datalen, s->far_max_ifp); + ast_log(LOG_WARNING, + "UDPTL asked to send %d bytes of IFP when far end only prepared to accept %d bytes; data loss may occur. " + "You may need to override the T38FaxMaxDatagram value for this endpoint in the channel driver configuration.\n", f->datalen, s->far_max_ifp); } /* Save seq_no for debug output because udptl_build_packet increments it */