/* }@ */
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 */
#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 */
int noncodeccapability; /*!< DTMF RFC2833 telephony-event */
int jointnoncodeccapability; /*!< Joint Non codec capability */
int redircodecs; /*!< Redirect codecs */
- int maxcallbitrate; /*!< Maximum Call Bitrate for Video Calls */
+ int maxcallbitrate; /*!< Maximum Call Bitrate for Video Calls */
+ int t38_maxdatagram; /*!< T.38 FaxMaxDatagram override */
struct sip_proxy *outboundproxy; /*!< Outbound proxy for this dialog */
struct t38properties t38; /*!< T38 settings */
struct sockaddr_in udptlredirip; /*!< Where our T.38 UDPTL should be going if not to us */
int capability; /*!< Codec capability */
int inUse; /*!< Number of calls in use */
int call_limit; /*!< Limit of concurrent calls */
+ int t38_maxdatagram; /*!< T.38 FaxMaxDatagram override */
enum transfermodes allowtransfer; /*! SIP Refer restriction scheme */
struct ast_ha *ha; /*!< ACL setting */
struct ast_variable *chanvars; /*!< Variables to set for channel created by user */
int onHold; /*!< Peer has someone on hold */
int call_limit; /*!< Limit of concurrent calls */
int busy_level; /*!< Level of active channels where we signal busy */
+ int t38_maxdatagram; /*!< T.38 FaxMaxDatagram override */
enum transfermodes allowtransfer; /*! SIP Refer restriction scheme */
char vmexten[AST_MAX_EXTENSION]; /*!< Dialplan extension for MWI notify message*/
char language[MAX_LANGUAGE]; /*!< Default language for prompts */
/* 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);
p->vrtp = ast_rtp_new_with_bindaddr(sched, io, 1, 0, bindaddr.sin_addr);
if (ast_test_flag(&p->flags[1], SIP_PAGE2_TEXTSUPPORT))
p->trtp = ast_rtp_new_with_bindaddr(sched, io, 1, 0, bindaddr.sin_addr);
- if (ast_test_flag(&p->flags[1], SIP_PAGE2_T38SUPPORT))
+ if (ast_test_flag(&p->flags[1], SIP_PAGE2_T38SUPPORT)) {
p->udptl = ast_udptl_new_with_bindaddr(sched, io, 0, bindaddr.sin_addr);
+ p->t38_maxdatagram = global_t38_maxdatagram;
+ }
if (!p->rtp|| (ast_test_flag(&p->flags[1], SIP_PAGE2_VIDEOSUPPORT) && !p->vrtp)
|| (ast_test_flag(&p->flags[1], SIP_PAGE2_TEXTSUPPORT) && !p->trtp)) {
ast_log(LOG_WARNING, "Unable to create RTP audio %s%ssession: %s\n",
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);
ast_rtp_destroy(p->trtp);
p->trtp = NULL;
}
+ if (p->udptl) {
+ p->t38_maxdatagram = user->t38_maxdatagram;
+ }
}
unref_user(user);
return res;
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);
}
ast_rtp_destroy(p->trtp);
p->trtp = NULL;
}
+ if (p->udptl) {
+ p->t38_maxdatagram = peer->t38_maxdatagram;
+ }
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;
}
}
+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[])
{
ast_cli(fd, " Insecure : %s\n", insecure2str(ast_test_flag(&peer->flags[0], SIP_INSECURE)));
ast_cli(fd, " Nat : %s\n", nat2str(ast_test_flag(&peer->flags[0], SIP_NAT)));
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, " CanReinvite : %s\n", cli_yesno(ast_test_flag(&peer->flags[0], SIP_CAN_REINVITE)));
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)));
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);
ast_cli(a->fd, " Record SIP history: %s\n", recordhistory ? "On" : "Off");
ast_cli(a->fd, " Call Events: %s\n", global_callevents ? "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 && !realtimeusers && !realtimeregs)
ast_cli(a->fd, " SIP realtime: Disabled\n" );
}
}
+/*!
+ \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 {
+ res = 0;
+ }
+
+ return res;
+}
+
/*!
\brief Handle flag-type options common to configuration of devices - users and peers
\param flags array of two struct ast_flags
} else if (!strcasecmp(v->name, "ignoresdpversion")) {
ast_set_flag(&mask[1], SIP_PAGE2_IGNORESDPVERSION);
ast_set2_flag(&flags[1], ast_true(v->value), SIP_PAGE2_IGNORESDPVERSION);
- } 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);
user->allowtransfer = global_allowtransfer;
user->maxcallbitrate = default_maxcallbitrate;
user->autoframing = global_autoframing;
+ user->t38_maxdatagram = global_t38_maxdatagram;
if (global_callcounter)
user->call_limit=999;
user->prefs = default_prefs;
for (; v || ((v = alt) && !(alt=NULL)); v = v->next) {
if (handle_common_options(&userflags[0], &mask[0], v))
continue;
+ if (handle_t38_options(&userflags[0], &mask[0], v, &user->t38_maxdatagram)) {
+ continue;
+ }
if (!strcasecmp(v->name, "context")) {
ast_copy_string(user->context, v->value, sizeof(user->context));
} else if (!strcasecmp(v->name, "subscribecontext")) {
peer->stimer.st_max_se = global_max_se;
peer->timer_t1 = global_t1;
peer->timer_b = global_timer_b;
+ peer->t38_maxdatagram = global_t38_maxdatagram;
clear_peer_mailboxes(peer);
}
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;
global_timer_b = 64 * SIP_TIMER_T1;
global_t1min = DEFAULT_T1MIN;
global_qualifyfreq = DEFAULT_QUALIFYFREQ;
+ global_t38_maxdatagram = -1;
global_matchexterniplocally = FALSE;
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;
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
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 */
}
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 */
ast_log(LOG_WARNING, "T38FaxUdpEC in udptl.conf is no longer supported; use the t38pt_udptl configuration option in sip.conf instead.\n");
}
if ((s = ast_variable_retrieve(cfg, "general", "T38FaxMaxDatagram"))) {
- udptlmaxdatagram = atoi(s);
- if (udptlmaxdatagram < 100) {
- ast_log(LOG_WARNING, "Too small T38FaxMaxDatagram size. Defaulting to 100.\n");
- udptlmaxdatagram = 100;
- }
- if (udptlmaxdatagram > LOCAL_FAX_MAX_DATAGRAM) {
- ast_log(LOG_WARNING, "Too large T38FaxMaxDatagram size. Defaulting to %d.\n", LOCAL_FAX_MAX_DATAGRAM);
- udptlmaxdatagram = LOCAL_FAX_MAX_DATAGRAM;
- }
+ ast_log(LOG_WARNING, "T38FaxMaxDatagram in udptl.conf is no longer supported.\n");
}
if ((s = ast_variable_retrieve(cfg, "general", "UDPTLFECentries"))) {
udptlfecentries = atoi(s);