UDPTL support for T.38 faxing. More...
#include "asterisk.h"#include <sys/time.h>#include <signal.h>#include <fcntl.h>#include "asterisk/udptl.h"#include "asterisk/frame.h"#include "asterisk/channel.h"#include "asterisk/acl.h"#include "asterisk/config.h"#include "asterisk/lock.h"#include "asterisk/utils.h"#include "asterisk/netsock.h"#include "asterisk/cli.h"#include "asterisk/unaligned.h"
Go to the source code of this file.
Data Structures | |
| struct | ast_udptl |
| Structure for an UDPTL session. More... | |
| struct | udptl_fec_rx_buffer_t |
| struct | udptl_fec_tx_buffer_t |
Defines | |
| #define | DEFAULT_FAX_MAX_DATAGRAM 400 |
| #define | FAX_MAX_DATAGRAM_LIMIT 1400 |
| #define | LOCAL_FAX_MAX_DATAGRAM 1400 |
| #define | LOG_TAG(u) S_OR(u->tag, "no tag") |
| #define | MAX_FEC_ENTRIES 5 |
| #define | MAX_FEC_SPAN 5 |
| #define | UDPTL_BUF_MASK 15 |
| #define | UDPTL_MTU 1200 |
Functions | |
| static void | __ast_udptl_reload (int reload) |
| static | AST_RWLIST_HEAD_STATIC (protos, ast_udptl_protocol) |
| int | ast_udptl_bridge (struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc) |
| void | ast_udptl_destroy (struct ast_udptl *udptl) |
| int | ast_udptl_fd (const struct ast_udptl *udptl) |
| enum ast_t38_ec_modes | ast_udptl_get_error_correction_scheme (const struct ast_udptl *udptl) |
| unsigned int | ast_udptl_get_far_max_datagram (const struct ast_udptl *udptl) |
| unsigned int | ast_udptl_get_far_max_ifp (struct ast_udptl *udptl) |
| retrieves far max ifp | |
| unsigned int | ast_udptl_get_local_max_datagram (struct ast_udptl *udptl) |
| retrieves local_max_datagram. | |
| void | ast_udptl_get_peer (const struct ast_udptl *udptl, struct sockaddr_in *them) |
| void | ast_udptl_get_us (const struct ast_udptl *udptl, struct sockaddr_in *us) |
| void | ast_udptl_init (void) |
| struct ast_udptl * | ast_udptl_new (struct sched_context *sched, struct io_context *io, int callbackmode) |
| struct ast_udptl * | ast_udptl_new_with_bindaddr (struct sched_context *sched, struct io_context *io, int callbackmode, struct in_addr addr) |
| int | ast_udptl_proto_register (struct ast_udptl_protocol *proto) |
| void | ast_udptl_proto_unregister (struct ast_udptl_protocol *proto) |
| struct ast_frame * | ast_udptl_read (struct ast_udptl *udptl) |
| int | ast_udptl_reload (void) |
| void | ast_udptl_set_callback (struct ast_udptl *udptl, ast_udptl_callback callback) |
| void | ast_udptl_set_data (struct ast_udptl *udptl, void *data) |
| void | ast_udptl_set_error_correction_scheme (struct ast_udptl *udptl, enum ast_t38_ec_modes ec) |
| void | ast_udptl_set_far_max_datagram (struct ast_udptl *udptl, unsigned int max_datagram) |
| sets far max datagram size. If max_datagram is = 0, the far max datagram size is set to a default value. | |
| void | ast_udptl_set_local_max_ifp (struct ast_udptl *udptl, unsigned int max_ifp) |
| void | ast_udptl_set_peer (struct ast_udptl *udptl, const struct sockaddr_in *them) |
| void | ast_udptl_set_tag (struct ast_udptl *udptl, const char *format,...) |
| Associates a character string 'tag' with a UDPTL session. | |
| void | ast_udptl_setnat (struct ast_udptl *udptl, int nat) |
| int | ast_udptl_setqos (struct ast_udptl *udptl, unsigned int tos, unsigned int cos) |
| void | ast_udptl_stop (struct ast_udptl *udptl) |
| int | ast_udptl_write (struct ast_udptl *s, struct ast_frame *f) |
| static void | calculate_far_max_ifp (struct ast_udptl *udptl) |
| static void | calculate_local_max_datagram (struct ast_udptl *udptl) |
| static int | decode_length (uint8_t *buf, unsigned int limit, unsigned int *len, unsigned int *pvalue) |
| static int | decode_open_type (uint8_t *buf, unsigned int limit, unsigned int *len, const uint8_t **p_object, unsigned int *p_num_octets) |
| static unsigned int | encode_length (uint8_t *buf, unsigned int *len, unsigned int value) |
| static int | encode_open_type (const struct ast_udptl *udptl, uint8_t *buf, unsigned int buflen, unsigned int *len, const uint8_t *data, unsigned int num_octets) |
| static struct ast_udptl_protocol * | get_proto (struct ast_channel *chan) |
| static char * | handle_cli_udptl_debug_deprecated (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
| static char * | handle_cli_udptl_set_debug (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
| static int | udptl_build_packet (struct ast_udptl *s, uint8_t *buf, unsigned int buflen, uint8_t *ifp, unsigned int ifp_len) |
| static int | udptl_debug_test_addr (const struct sockaddr_in *addr) |
| static int | udptl_rx_packet (struct ast_udptl *s, uint8_t *buf, unsigned int len) |
| static int | udptlread (int *id, int fd, short events, void *cbdata) |
Variables | |
| static struct ast_cli_entry | cli_handle_udptl_debug_deprecated = AST_CLI_DEFINE(handle_cli_udptl_debug_deprecated, "Enable/Disable UDPTL debugging") |
| static struct ast_cli_entry | cli_udptl [] |
| static int | udptldebug |
| static struct sockaddr_in | udptldebugaddr |
| static int | udptlend = 4599 |
| static int | udptlfecentries |
| static int | udptlfecspan |
| static int | udptlstart = 4500 |
| static int | use_even_ports |
UDPTL support for T.38 faxing.
Definition in file udptl.c.
| #define DEFAULT_FAX_MAX_DATAGRAM 400 |
Definition at line 94 of file udptl.c.
Referenced by ast_udptl_set_far_max_datagram(), and ast_udptl_write().
| #define FAX_MAX_DATAGRAM_LIMIT 1400 |
Definition at line 95 of file udptl.c.
Referenced by ast_udptl_set_far_max_datagram().
| #define LOCAL_FAX_MAX_DATAGRAM 1400 |
Definition at line 93 of file udptl.c.
Referenced by calculate_local_max_datagram(), udptl_build_packet(), and udptl_rx_packet().
| #define LOG_TAG | ( | u | ) | S_OR(u->tag, "no tag") |
Definition at line 80 of file udptl.c.
Referenced by ast_udptl_read(), ast_udptl_write(), calculate_far_max_ifp(), calculate_local_max_datagram(), encode_open_type(), and udptl_build_packet().
| #define MAX_FEC_ENTRIES 5 |
Definition at line 96 of file udptl.c.
Referenced by __ast_udptl_reload().
| #define MAX_FEC_SPAN 5 |
Definition at line 97 of file udptl.c.
Referenced by __ast_udptl_reload().
| #define UDPTL_BUF_MASK 15 |
Definition at line 99 of file udptl.c.
Referenced by ast_udptl_new_with_bindaddr(), udptl_build_packet(), and udptl_rx_packet().
| static void __ast_udptl_reload | ( | int | reload | ) | [static] |
Definition at line 1396 of file udptl.c.
References ast_config_destroy(), ast_config_load2(), ast_false(), ast_log(), ast_true(), ast_variable_retrieve(), ast_verb, CONFIG_FLAG_FILEUNCHANGED, CONFIG_STATUS_FILEUNCHANGED, LOG_NOTICE, LOG_WARNING, MAX_FEC_ENTRIES, MAX_FEC_SPAN, and s.
Referenced by ast_udptl_init(), and ast_udptl_reload().
01397 { 01398 struct ast_config *cfg; 01399 const char *s; 01400 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 }; 01401 01402 if ((cfg = ast_config_load2("udptl.conf", "udptl", config_flags)) == CONFIG_STATUS_FILEUNCHANGED) 01403 return; 01404 01405 udptlstart = 4500; 01406 udptlend = 4999; 01407 udptlfecentries = 0; 01408 udptlfecspan = 0; 01409 use_even_ports = 0; 01410 01411 if (cfg) { 01412 if ((s = ast_variable_retrieve(cfg, "general", "udptlstart"))) { 01413 udptlstart = atoi(s); 01414 if (udptlstart < 1024) { 01415 ast_log(LOG_WARNING, "Ports under 1024 are not allowed for T.38.\n"); 01416 udptlstart = 1024; 01417 } 01418 if (udptlstart > 65535) { 01419 ast_log(LOG_WARNING, "Ports over 65535 are invalid.\n"); 01420 udptlstart = 65535; 01421 } 01422 } 01423 if ((s = ast_variable_retrieve(cfg, "general", "udptlend"))) { 01424 udptlend = atoi(s); 01425 if (udptlend < 1024) { 01426 ast_log(LOG_WARNING, "Ports under 1024 are not allowed for T.38.\n"); 01427 udptlend = 1024; 01428 } 01429 if (udptlend > 65535) { 01430 ast_log(LOG_WARNING, "Ports over 65535 are invalid.\n"); 01431 udptlend = 65535; 01432 } 01433 } 01434 if ((s = ast_variable_retrieve(cfg, "general", "udptlchecksums"))) { 01435 #ifdef SO_NO_CHECK 01436 if (ast_false(s)) 01437 nochecksums = 1; 01438 else 01439 nochecksums = 0; 01440 #else 01441 if (ast_false(s)) 01442 ast_log(LOG_WARNING, "Disabling UDPTL checksums is not supported on this operating system!\n"); 01443 #endif 01444 } 01445 if ((s = ast_variable_retrieve(cfg, "general", "T38FaxUdpEC"))) { 01446 ast_log(LOG_WARNING, "T38FaxUdpEC in udptl.conf is no longer supported; use the t38pt_udptl configuration option in sip.conf instead.\n"); 01447 } 01448 if ((s = ast_variable_retrieve(cfg, "general", "T38FaxMaxDatagram"))) { 01449 ast_log(LOG_WARNING, "T38FaxMaxDatagram in udptl.conf is no longer supported; value is now supplied by T.38 applications.\n"); 01450 } 01451 if ((s = ast_variable_retrieve(cfg, "general", "UDPTLFECEntries"))) { 01452 udptlfecentries = atoi(s); 01453 if (udptlfecentries < 1) { 01454 ast_log(LOG_WARNING, "Too small UDPTLFECEntries value. Defaulting to 1.\n"); 01455 udptlfecentries = 1; 01456 } 01457 if (udptlfecentries > MAX_FEC_ENTRIES) { 01458 ast_log(LOG_WARNING, "Too large UDPTLFECEntries value. Defaulting to %d.\n", MAX_FEC_ENTRIES); 01459 udptlfecentries = MAX_FEC_ENTRIES; 01460 } 01461 } 01462 if ((s = ast_variable_retrieve(cfg, "general", "UDPTLFECSpan"))) { 01463 udptlfecspan = atoi(s); 01464 if (udptlfecspan < 1) { 01465 ast_log(LOG_WARNING, "Too small UDPTLFECSpan value. Defaulting to 1.\n"); 01466 udptlfecspan = 1; 01467 } 01468 if (udptlfecspan > MAX_FEC_SPAN) { 01469 ast_log(LOG_WARNING, "Too large UDPTLFECSpan value. Defaulting to %d.\n", MAX_FEC_SPAN); 01470 udptlfecspan = MAX_FEC_SPAN; 01471 } 01472 } 01473 if ((s = ast_variable_retrieve(cfg, "general", "use_even_ports"))) { 01474 use_even_ports = ast_true(s); 01475 } 01476 ast_config_destroy(cfg); 01477 } 01478 if (udptlstart >= udptlend) { 01479 ast_log(LOG_WARNING, "Unreasonable values for UDPTL start/end ports; defaulting to 4500-4999.\n"); 01480 udptlstart = 4500; 01481 udptlend = 4999; 01482 } 01483 if (use_even_ports && (udptlstart & 1)) { 01484 ++udptlstart; 01485 ast_log(LOG_NOTICE, "Odd numbered udptlstart specified but use_even_ports enabled. udptlstart is now %d\n", udptlstart); 01486 } 01487 if (use_even_ports && (udptlend & 1)) { 01488 --udptlend; 01489 ast_log(LOG_NOTICE, "Odd numbered udptlend specified but use_event_ports enabled. udptlend is now %d\n", udptlend); 01490 } 01491 ast_verb(2, "UDPTL allocating from port range %d -> %d\n", udptlstart, udptlend); 01492 }
| static AST_RWLIST_HEAD_STATIC | ( | protos | , | |
| ast_udptl_protocol | ||||
| ) | [static] |
| int ast_udptl_bridge | ( | struct ast_channel * | c0, | |
| struct ast_channel * | c1, | |||
| int | flags, | |||
| struct ast_frame ** | fo, | |||
| struct ast_channel ** | rc | |||
| ) |
Definition at line 1143 of file udptl.c.
References ast_channel_lock, ast_channel_trylock, ast_channel_unlock, ast_check_hangup(), ast_debug, AST_FRAME_MODEM, ast_frfree, ast_inet_ntoa(), ast_log(), ast_read(), ast_udptl_get_peer(), ast_waitfor_n(), ast_write(), f, ast_frame::frametype, get_proto(), ast_udptl_protocol::get_udptl_info, inaddrcmp(), LOG_WARNING, ast_channel::masq, ast_channel::masqr, ast_udptl_protocol::set_udptl_peer, and ast_channel::tech_pvt.
01144 { 01145 struct ast_frame *f; 01146 struct ast_channel *who; 01147 struct ast_channel *cs[3]; 01148 struct ast_udptl *p0; 01149 struct ast_udptl *p1; 01150 struct ast_udptl_protocol *pr0; 01151 struct ast_udptl_protocol *pr1; 01152 struct sockaddr_in ac0; 01153 struct sockaddr_in ac1; 01154 struct sockaddr_in t0; 01155 struct sockaddr_in t1; 01156 void *pvt0; 01157 void *pvt1; 01158 int to; 01159 01160 ast_channel_lock(c0); 01161 while (ast_channel_trylock(c1)) { 01162 ast_channel_unlock(c0); 01163 usleep(1); 01164 ast_channel_lock(c0); 01165 } 01166 pr0 = get_proto(c0); 01167 pr1 = get_proto(c1); 01168 if (!pr0) { 01169 ast_log(LOG_WARNING, "Can't find native functions for channel '%s'\n", c0->name); 01170 ast_channel_unlock(c0); 01171 ast_channel_unlock(c1); 01172 return -1; 01173 } 01174 if (!pr1) { 01175 ast_log(LOG_WARNING, "Can't find native functions for channel '%s'\n", c1->name); 01176 ast_channel_unlock(c0); 01177 ast_channel_unlock(c1); 01178 return -1; 01179 } 01180 pvt0 = c0->tech_pvt; 01181 pvt1 = c1->tech_pvt; 01182 p0 = pr0->get_udptl_info(c0); 01183 p1 = pr1->get_udptl_info(c1); 01184 if (!p0 || !p1) { 01185 /* Somebody doesn't want to play... */ 01186 ast_channel_unlock(c0); 01187 ast_channel_unlock(c1); 01188 return -2; 01189 } 01190 if (pr0->set_udptl_peer(c0, p1)) { 01191 ast_log(LOG_WARNING, "Channel '%s' failed to talk to '%s'\n", c0->name, c1->name); 01192 memset(&ac1, 0, sizeof(ac1)); 01193 } else { 01194 /* Store UDPTL peer */ 01195 ast_udptl_get_peer(p1, &ac1); 01196 } 01197 if (pr1->set_udptl_peer(c1, p0)) { 01198 ast_log(LOG_WARNING, "Channel '%s' failed to talk back to '%s'\n", c1->name, c0->name); 01199 memset(&ac0, 0, sizeof(ac0)); 01200 } else { 01201 /* Store UDPTL peer */ 01202 ast_udptl_get_peer(p0, &ac0); 01203 } 01204 ast_channel_unlock(c0); 01205 ast_channel_unlock(c1); 01206 cs[0] = c0; 01207 cs[1] = c1; 01208 cs[2] = NULL; 01209 for (;;) { 01210 if ((c0->tech_pvt != pvt0) || 01211 (c1->tech_pvt != pvt1) || 01212 (c0->masq || c0->masqr || c1->masq || c1->masqr)) { 01213 ast_debug(1, "Oooh, something is weird, backing out\n"); 01214 /* Tell it to try again later */ 01215 return -3; 01216 } 01217 to = -1; 01218 ast_udptl_get_peer(p1, &t1); 01219 ast_udptl_get_peer(p0, &t0); 01220 if (inaddrcmp(&t1, &ac1)) { 01221 ast_debug(1, "Oooh, '%s' changed end address to %s:%d\n", 01222 c1->name, ast_inet_ntoa(t1.sin_addr), ntohs(t1.sin_port)); 01223 ast_debug(1, "Oooh, '%s' was %s:%d\n", 01224 c1->name, ast_inet_ntoa(ac1.sin_addr), ntohs(ac1.sin_port)); 01225 memcpy(&ac1, &t1, sizeof(ac1)); 01226 } 01227 if (inaddrcmp(&t0, &ac0)) { 01228 ast_debug(1, "Oooh, '%s' changed end address to %s:%d\n", 01229 c0->name, ast_inet_ntoa(t0.sin_addr), ntohs(t0.sin_port)); 01230 ast_debug(1, "Oooh, '%s' was %s:%d\n", 01231 c0->name, ast_inet_ntoa(ac0.sin_addr), ntohs(ac0.sin_port)); 01232 memcpy(&ac0, &t0, sizeof(ac0)); 01233 } 01234 who = ast_waitfor_n(cs, 2, &to); 01235 if (!who) { 01236 ast_debug(1, "Ooh, empty read...\n"); 01237 /* check for hangup / whentohangup */ 01238 if (ast_check_hangup(c0) || ast_check_hangup(c1)) 01239 break; 01240 continue; 01241 } 01242 f = ast_read(who); 01243 if (!f) { 01244 *fo = f; 01245 *rc = who; 01246 ast_debug(1, "Oooh, got a %s\n", f ? "digit" : "hangup"); 01247 /* That's all we needed */ 01248 return 0; 01249 } else { 01250 if (f->frametype == AST_FRAME_MODEM) { 01251 /* Forward T.38 frames if they happen upon us */ 01252 if (who == c0) { 01253 ast_write(c1, f); 01254 } else if (who == c1) { 01255 ast_write(c0, f); 01256 } 01257 } 01258 ast_frfree(f); 01259 } 01260 /* Swap priority. Not that it's a big deal at this point */ 01261 cs[2] = cs[0]; 01262 cs[0] = cs[1]; 01263 cs[1] = cs[2]; 01264 } 01265 return -1; 01266 }
| void ast_udptl_destroy | ( | struct ast_udptl * | udptl | ) |
Definition at line 1042 of file udptl.c.
References ast_free, ast_io_remove(), ast_udptl::fd, ast_udptl::io, ast_udptl::ioid, and ast_udptl::tag.
Referenced by __sip_destroy(), and create_addr_from_peer().
| int ast_udptl_fd | ( | const struct ast_udptl * | udptl | ) |
Definition at line 640 of file udptl.c.
References ast_udptl::fd.
Referenced by __oh323_new(), and sip_new().
00641 { 00642 return udptl->fd; 00643 }
| enum ast_t38_ec_modes ast_udptl_get_error_correction_scheme | ( | const struct ast_udptl * | udptl | ) |
Definition at line 824 of file udptl.c.
References ast_udptl::error_correction_scheme.
Referenced by add_sdp().
00825 { 00826 return udptl->error_correction_scheme; 00827 }
| unsigned int ast_udptl_get_far_max_datagram | ( | const struct ast_udptl * | udptl | ) |
Definition at line 892 of file udptl.c.
References ast_udptl::far_max_datagram.
Referenced by process_sdp().
00893 { 00894 if (udptl->far_max_datagram < 0) { 00895 return 0; 00896 } 00897 return udptl->far_max_datagram; 00898 }
| unsigned int ast_udptl_get_far_max_ifp | ( | struct ast_udptl * | udptl | ) |
retrieves far max ifp
| positive | value representing max ifp size | |
| 0 | if no value is present |
Definition at line 900 of file udptl.c.
References calculate_far_max_ifp(), and ast_udptl::far_max_ifp.
Referenced by change_t38_state().
00901 { 00902 if (udptl->far_max_ifp == -1) { 00903 calculate_far_max_ifp(udptl); 00904 } 00905 00906 if (udptl->far_max_ifp < 0) { 00907 return 0; 00908 } 00909 return udptl->far_max_ifp; 00910 }
| unsigned int ast_udptl_get_local_max_datagram | ( | struct ast_udptl * | udptl | ) |
retrieves local_max_datagram.
| positive | value representing max datagram size. | |
| 0 | if no value is present |
Definition at line 868 of file udptl.c.
References calculate_local_max_datagram(), and ast_udptl::local_max_datagram.
Referenced by add_sdp().
00869 { 00870 if (udptl->local_max_datagram == -1) { 00871 calculate_local_max_datagram(udptl); 00872 } 00873 00874 /* this function expects a unsigned value in return. */ 00875 if (udptl->local_max_datagram < 0) { 00876 return 0; 00877 } 00878 return udptl->local_max_datagram; 00879 }
| void ast_udptl_get_peer | ( | const struct ast_udptl * | udptl, | |
| struct sockaddr_in * | them | |||
| ) |
Definition at line 1023 of file udptl.c.
References ast_udptl::them.
Referenced by ast_udptl_bridge(), and sip_set_udptl_peer().
| void ast_udptl_get_us | ( | const struct ast_udptl * | udptl, | |
| struct sockaddr_in * | us | |||
| ) |
| void ast_udptl_init | ( | void | ) |
Definition at line 1500 of file udptl.c.
References __ast_udptl_reload(), and ast_cli_register_multiple().
Referenced by main().
01501 { 01502 ast_cli_register_multiple(cli_udptl, sizeof(cli_udptl) / sizeof(struct ast_cli_entry)); 01503 __ast_udptl_reload(0); 01504 }
| struct ast_udptl* ast_udptl_new | ( | struct sched_context * | sched, | |
| struct io_context * | io, | |||
| int | callbackmode | |||
| ) | [read] |
Definition at line 990 of file udptl.c.
References ast_udptl_new_with_bindaddr().
00991 { 00992 struct in_addr ia; 00993 memset(&ia, 0, sizeof(ia)); 00994 return ast_udptl_new_with_bindaddr(sched, io, callbackmode, ia); 00995 }
| struct ast_udptl* ast_udptl_new_with_bindaddr | ( | struct sched_context * | sched, | |
| struct io_context * | io, | |||
| int | callbackmode, | |||
| struct in_addr | addr | |||
| ) | [read] |
Definition at line 912 of file udptl.c.
References ast_calloc, ast_free, ast_io_add(), AST_IO_IN, ast_log(), ast_random(), udptl_fec_tx_buffer_t::buf_len, udptl_fec_rx_buffer_t::buf_len, errno, ast_udptl::error_correction_entries, ast_udptl::error_correction_span, ast_udptl::far_max_datagram, ast_udptl::far_max_ifp, ast_udptl::fd, ast_udptl::flags, ast_udptl::io, ast_udptl::ioid, ast_udptl::local_max_datagram, ast_udptl::local_max_ifp, LOG_WARNING, ast_udptl::rx, ast_udptl::sched, ast_udptl::them, ast_udptl::tx, UDPTL_BUF_MASK, udptlread(), and ast_udptl::us.
Referenced by ast_udptl_new(), create_addr_from_peer(), handle_request_invite(), and sip_alloc().
00913 { 00914 struct ast_udptl *udptl; 00915 int x; 00916 int startplace; 00917 int i; 00918 long int flags; 00919 00920 if (!(udptl = ast_calloc(1, sizeof(*udptl)))) 00921 return NULL; 00922 00923 udptl->error_correction_span = udptlfecspan; 00924 udptl->error_correction_entries = udptlfecentries; 00925 00926 udptl->far_max_datagram = -1; 00927 udptl->far_max_ifp = -1; 00928 udptl->local_max_ifp = -1; 00929 udptl->local_max_datagram = -1; 00930 00931 for (i = 0; i <= UDPTL_BUF_MASK; i++) { 00932 udptl->rx[i].buf_len = -1; 00933 udptl->tx[i].buf_len = -1; 00934 } 00935 00936 udptl->them.sin_family = AF_INET; 00937 udptl->us.sin_family = AF_INET; 00938 00939 if ((udptl->fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 00940 ast_free(udptl); 00941 ast_log(LOG_WARNING, "Unable to allocate socket: %s\n", strerror(errno)); 00942 return NULL; 00943 } 00944 flags = fcntl(udptl->fd, F_GETFL); 00945 fcntl(udptl->fd, F_SETFL, flags | O_NONBLOCK); 00946 #ifdef SO_NO_CHECK 00947 if (nochecksums) 00948 setsockopt(udptl->fd, SOL_SOCKET, SO_NO_CHECK, &nochecksums, sizeof(nochecksums)); 00949 #endif 00950 /* Find us a place */ 00951 x = (udptlstart == udptlend) ? udptlstart : (ast_random() % (udptlend - udptlstart)) + udptlstart; 00952 if (use_even_ports && (x & 1)) { 00953 ++x; 00954 } 00955 startplace = x; 00956 for (;;) { 00957 udptl->us.sin_port = htons(x); 00958 udptl->us.sin_addr = addr; 00959 if (bind(udptl->fd, (struct sockaddr *) &udptl->us, sizeof(udptl->us)) == 0) 00960 break; 00961 if (errno != EADDRINUSE) { 00962 ast_log(LOG_WARNING, "Unexpected bind error: %s\n", strerror(errno)); 00963 close(udptl->fd); 00964 ast_free(udptl); 00965 return NULL; 00966 } 00967 if (use_even_ports) { 00968 x += 2; 00969 } else { 00970 ++x; 00971 } 00972 if (x > udptlend) 00973 x = udptlstart; 00974 if (x == startplace) { 00975 ast_log(LOG_WARNING, "No UDPTL ports remaining\n"); 00976 close(udptl->fd); 00977 ast_free(udptl); 00978 return NULL; 00979 } 00980 } 00981 if (io && sched && callbackmode) { 00982 /* Operate this one in a callback mode */ 00983 udptl->sched = sched; 00984 udptl->io = io; 00985 udptl->ioid = ast_io_add(udptl->io, udptl->fd, udptlread, AST_IO_IN, udptl); 00986 } 00987 return udptl; 00988 }
| int ast_udptl_proto_register | ( | struct ast_udptl_protocol * | proto | ) |
Definition at line 1112 of file udptl.c.
References ast_log(), AST_RWLIST_INSERT_TAIL, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_udptl_protocol::list, LOG_WARNING, and ast_udptl_protocol::type.
Referenced by load_module().
01113 { 01114 struct ast_udptl_protocol *cur; 01115 01116 AST_RWLIST_WRLOCK(&protos); 01117 AST_RWLIST_TRAVERSE(&protos, cur, list) { 01118 if (cur->type == proto->type) { 01119 ast_log(LOG_WARNING, "Tried to register same protocol '%s' twice\n", cur->type); 01120 AST_RWLIST_UNLOCK(&protos); 01121 return -1; 01122 } 01123 } 01124 AST_RWLIST_INSERT_TAIL(&protos, proto, list); 01125 AST_RWLIST_UNLOCK(&protos); 01126 return 0; 01127 }
| void ast_udptl_proto_unregister | ( | struct ast_udptl_protocol * | proto | ) |
Definition at line 1105 of file udptl.c.
References AST_RWLIST_REMOVE, AST_RWLIST_UNLOCK, and AST_RWLIST_WRLOCK.
Referenced by unload_module().
01106 { 01107 AST_RWLIST_WRLOCK(&protos); 01108 AST_RWLIST_REMOVE(&protos, proto, list); 01109 AST_RWLIST_UNLOCK(&protos); 01110 }
Definition at line 672 of file udptl.c.
References ast_assert, ast_debug, AST_FRIENDLY_OFFSET, ast_inet_ntoa(), ast_log(), ast_null_frame, ast_verb, errno, ast_udptl::f, ast_udptl::fd, len(), LOG_TAG, LOG_WARNING, ast_udptl::nat, ast_udptl::rawdata, ast_udptl::them, udptl_debug_test_addr(), and udptl_rx_packet().
Referenced by sip_rtp_read(), skinny_rtp_read(), and udptlread().
00673 { 00674 int res; 00675 struct sockaddr_in sin; 00676 socklen_t len; 00677 uint16_t seqno = 0; 00678 uint16_t *udptlheader; 00679 00680 len = sizeof(sin); 00681 00682 /* Cache where the header will go */ 00683 res = recvfrom(udptl->fd, 00684 udptl->rawdata + AST_FRIENDLY_OFFSET, 00685 sizeof(udptl->rawdata) - AST_FRIENDLY_OFFSET, 00686 0, 00687 (struct sockaddr *) &sin, 00688 &len); 00689 udptlheader = (uint16_t *)(udptl->rawdata + AST_FRIENDLY_OFFSET); 00690 if (res < 0) { 00691 if (errno != EAGAIN) 00692 ast_log(LOG_WARNING, "(%s): UDPTL read error: %s\n", 00693 LOG_TAG(udptl), strerror(errno)); 00694 ast_assert(errno != EBADF); 00695 return &ast_null_frame; 00696 } 00697 00698 /* Ignore if the other side hasn't been given an address yet. */ 00699 if (!udptl->them.sin_addr.s_addr || !udptl->them.sin_port) 00700 return &ast_null_frame; 00701 00702 if (udptl->nat) { 00703 /* Send to whoever sent to us */ 00704 if ((udptl->them.sin_addr.s_addr != sin.sin_addr.s_addr) || 00705 (udptl->them.sin_port != sin.sin_port)) { 00706 memcpy(&udptl->them, &sin, sizeof(udptl->them)); 00707 ast_debug(1, "UDPTL NAT (%s): Using address %s:%d\n", 00708 LOG_TAG(udptl), ast_inet_ntoa(udptl->them.sin_addr), ntohs(udptl->them.sin_port)); 00709 } 00710 } 00711 00712 if (udptl_debug_test_addr(&sin)) { 00713 ast_verb(1, "UDPTL (%s): packet from %s:%d (type %d, seq %d, len %d)\n", 00714 LOG_TAG(udptl), ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port), 0, seqno, res); 00715 } 00716 if (udptl_rx_packet(udptl, udptl->rawdata + AST_FRIENDLY_OFFSET, res) < 1) 00717 return &ast_null_frame; 00718 00719 return &udptl->f[0]; 00720 }
| int ast_udptl_reload | ( | void | ) |
Definition at line 1494 of file udptl.c.
References __ast_udptl_reload().
01495 { 01496 __ast_udptl_reload(1); 01497 return 0; 01498 }
| void ast_udptl_set_callback | ( | struct ast_udptl * | udptl, | |
| ast_udptl_callback | callback | |||
| ) |
Definition at line 650 of file udptl.c.
References ast_udptl::callback.
00651 { 00652 udptl->callback = callback; 00653 }
| void ast_udptl_set_data | ( | struct ast_udptl * | udptl, | |
| void * | data | |||
| ) |
Definition at line 645 of file udptl.c.
References ast_udptl::data.
00646 { 00647 udptl->data = data; 00648 }
| void ast_udptl_set_error_correction_scheme | ( | struct ast_udptl * | udptl, | |
| enum ast_t38_ec_modes | ec | |||
| ) |
Definition at line 829 of file udptl.c.
References ast_udptl::error_correction_entries, ast_udptl::error_correction_scheme, ast_udptl::error_correction_span, ast_udptl::far_max_ifp, ast_udptl::local_max_datagram, UDPTL_ERROR_CORRECTION_FEC, and UDPTL_ERROR_CORRECTION_REDUNDANCY.
Referenced by process_sdp_a_image(), and set_t38_capabilities().
00830 { 00831 udptl->error_correction_scheme = ec; 00832 switch (ec) { 00833 case UDPTL_ERROR_CORRECTION_FEC: 00834 udptl->error_correction_scheme = UDPTL_ERROR_CORRECTION_FEC; 00835 if (udptl->error_correction_entries == 0) { 00836 udptl->error_correction_entries = 3; 00837 } 00838 if (udptl->error_correction_span == 0) { 00839 udptl->error_correction_span = 3; 00840 } 00841 break; 00842 case UDPTL_ERROR_CORRECTION_REDUNDANCY: 00843 udptl->error_correction_scheme = UDPTL_ERROR_CORRECTION_REDUNDANCY; 00844 if (udptl->error_correction_entries == 0) { 00845 udptl->error_correction_entries = 3; 00846 } 00847 break; 00848 default: 00849 /* nothing to do */ 00850 break; 00851 }; 00852 /* reset calculated values so they'll be computed again */ 00853 udptl->local_max_datagram = -1; 00854 udptl->far_max_ifp = -1; 00855 }
| void ast_udptl_set_far_max_datagram | ( | struct ast_udptl * | udptl, | |
| unsigned int | max_datagram | |||
| ) |
sets far max datagram size. If max_datagram is = 0, the far max datagram size is set to a default value.
Definition at line 881 of file udptl.c.
References DEFAULT_FAX_MAX_DATAGRAM, ast_udptl::far_max_datagram, ast_udptl::far_max_ifp, and FAX_MAX_DATAGRAM_LIMIT.
Referenced by process_sdp(), and process_sdp_a_image().
00882 { 00883 if (!max_datagram || (max_datagram > FAX_MAX_DATAGRAM_LIMIT)) { 00884 udptl->far_max_datagram = DEFAULT_FAX_MAX_DATAGRAM; 00885 } else { 00886 udptl->far_max_datagram = max_datagram; 00887 } 00888 /* reset calculated values so they'll be computed again */ 00889 udptl->far_max_ifp = -1; 00890 }
| void ast_udptl_set_local_max_ifp | ( | struct ast_udptl * | udptl, | |
| unsigned int | max_ifp | |||
| ) |
Definition at line 857 of file udptl.c.
References ast_udptl::local_max_datagram, and ast_udptl::local_max_ifp.
Referenced by interpret_t38_parameters().
00858 { 00859 /* make sure max_ifp is a positive value since a cast will take place when 00860 * when setting local_max_ifp */ 00861 if ((signed int) max_ifp > 0) { 00862 udptl->local_max_ifp = max_ifp; 00863 /* reset calculated values so they'll be computed again */ 00864 udptl->local_max_datagram = -1; 00865 } 00866 }
| void ast_udptl_set_peer | ( | struct ast_udptl * | udptl, | |
| const struct sockaddr_in * | them | |||
| ) |
| void ast_udptl_set_tag | ( | struct ast_udptl * | udptl, | |
| const char * | format, | |||
| ... | ||||
| ) |
Associates a character string 'tag' with a UDPTL session.
| udptl | The UDPTL session. | |
| format | printf-style format string used to construct the tag |
This function formats a tag for the specified UDPTL session, so that any log messages generated by the UDPTL stack related to that session will include the tag and the reader of the messages will be able to identify which endpoint caused them to be generated.
| none |
Definition at line 997 of file udptl.c.
References ast_free, ast_vasprintf, and ast_udptl::tag.
Referenced by change_t38_state().
| void ast_udptl_setnat | ( | struct ast_udptl * | udptl, | |
| int | nat | |||
| ) |
| int ast_udptl_setqos | ( | struct ast_udptl * | udptl, | |
| unsigned int | tos, | |||
| unsigned int | cos | |||
| ) |
Definition at line 1012 of file udptl.c.
References ast_netsock_set_qos(), and ast_udptl::fd.
Referenced by sip_alloc().
01013 { 01014 return ast_netsock_set_qos(udptl->fd, tos, cos, "UDPTL"); 01015 }
| void ast_udptl_stop | ( | struct ast_udptl * | udptl | ) |
Definition at line 1036 of file udptl.c.
References ast_udptl::them.
Referenced by process_sdp(), and stop_media_flows().
Definition at line 1053 of file udptl.c.
References AST_FRAME_MODEM, ast_inet_ntoa(), ast_log(), AST_MODEM_T38, ast_verb, buf, ast_frame::data, ast_frame::datalen, DEFAULT_FAX_MAX_DATAGRAM, errno, ast_udptl::far_max_datagram, ast_udptl::far_max_ifp, ast_udptl::fd, ast_frame::frametype, len(), LOG_NOTICE, LOG_TAG, LOG_WARNING, ast_frame::ptr, seq, ast_frame::subclass, ast_udptl::them, ast_udptl::tx_seq_no, udptl_build_packet(), and udptl_debug_test_addr().
Referenced by sip_write().
01054 { 01055 unsigned int seq; 01056 unsigned int len = f->datalen; 01057 int res; 01058 /* if no max datagram size is provided, use default value */ 01059 const int bufsize = (s->far_max_datagram > 0) ? s->far_max_datagram : DEFAULT_FAX_MAX_DATAGRAM; 01060 uint8_t buf[bufsize]; 01061 01062 memset(buf, 0, sizeof(buf)); 01063 01064 /* If we have no peer, return immediately */ 01065 if (s->them.sin_addr.s_addr == INADDR_ANY) 01066 return 0; 01067 01068 /* If there is no data length, return immediately */ 01069 if (f->datalen == 0) 01070 return 0; 01071 01072 if ((f->frametype != AST_FRAME_MODEM) || 01073 (f->subclass != AST_MODEM_T38)) { 01074 ast_log(LOG_WARNING, "(%s): UDPTL can only send T.38 data.\n", 01075 LOG_TAG(s)); 01076 return -1; 01077 } 01078 01079 if (len > s->far_max_ifp) { 01080 ast_log(LOG_WARNING, 01081 "(%s): UDPTL asked to send %d bytes of IFP when far end only prepared to accept %d bytes; data loss will occur." 01082 "You may need to override the T38FaxMaxDatagram value for this endpoint in the channel driver configuration.\n", 01083 LOG_TAG(s), len, s->far_max_ifp); 01084 len = s->far_max_ifp; 01085 } 01086 01087 /* Save seq_no for debug output because udptl_build_packet increments it */ 01088 seq = s->tx_seq_no & 0xFFFF; 01089 01090 /* Cook up the UDPTL packet, with the relevant EC info. */ 01091 len = udptl_build_packet(s, buf, sizeof(buf), f->data.ptr, len); 01092 01093 if (len > 0 && s->them.sin_port && s->them.sin_addr.s_addr) { 01094 if ((res = sendto(s->fd, buf, len, 0, (struct sockaddr *) &s->them, sizeof(s->them))) < 0) 01095 ast_log(LOG_NOTICE, "(%s): UDPTL Transmission error to %s:%d: %s\n", 01096 LOG_TAG(s), ast_inet_ntoa(s->them.sin_addr), ntohs(s->them.sin_port), strerror(errno)); 01097 if (udptl_debug_test_addr(&s->them)) 01098 ast_verb(1, "UDPTL (%s): packet to %s:%d (type %d, seq %d, len %d)\n", 01099 LOG_TAG(s), ast_inet_ntoa(s->them.sin_addr), ntohs(s->them.sin_port), 0, seq, len); 01100 } 01101 01102 return 0; 01103 }
| static void calculate_far_max_ifp | ( | struct ast_udptl * | udptl | ) | [static] |
Definition at line 763 of file udptl.c.
References ast_log(), ast_udptl::error_correction_entries, ast_udptl::error_correction_scheme, ast_udptl::far_max_datagram, ast_udptl::far_max_ifp, LOG_TAG, LOG_WARNING, UDPTL_ERROR_CORRECTION_FEC, UDPTL_ERROR_CORRECTION_NONE, and UDPTL_ERROR_CORRECTION_REDUNDANCY.
Referenced by ast_udptl_get_far_max_ifp().
00764 { 00765 unsigned new_max = 0; 00766 00767 if (udptl->far_max_datagram == -1) { 00768 ast_log(LOG_WARNING, "(%s): Cannot calculate far_max_ifp before far_max_datagram has been set.\n", 00769 LOG_TAG(udptl)); 00770 udptl->far_max_ifp = -1; 00771 return; 00772 } 00773 00774 /* the goal here is to supply the local endpoint (application 00775 * or bridged channel) a maximum IFP value that will allow it 00776 * to effectively and efficiently transfer image data at its 00777 * selected bit rate, taking into account the selected error 00778 * correction mode, but without overrunning the far endpoint's 00779 * datagram buffer. this is complicated by the fact that some 00780 * far endpoints send us bogus (small) max datagram values, 00781 * which would result in either buffer overrun or no error 00782 * correction. we try to accomodate those, but if the supplied 00783 * value is too small to do so, we'll emit warning messages and 00784 * the user will have to use configuration options to override 00785 * the max datagram value supplied by the far endpoint. 00786 */ 00787 switch (udptl->error_correction_scheme) { 00788 case UDPTL_ERROR_CORRECTION_NONE: 00789 /* need room for sequence number, length indicator, redundancy 00790 * indicator and following length indicator 00791 */ 00792 new_max = udptl->far_max_datagram - 5; 00793 break; 00794 case UDPTL_ERROR_CORRECTION_REDUNDANCY: 00795 /* for this case, we'd like to send as many error correction entries 00796 * as possible (up to the number we're configured for), but we'll settle 00797 * for sending fewer if the configured number would cause the 00798 * calculated max IFP to be too small for effective operation 00799 * 00800 * need room for sequence number, length indicators and the 00801 * configured number of redundant packets 00802 * 00803 * note: we purposely don't allow error_correction_entries to drop to 00804 * zero in this loop; we'd rather send smaller IFPs (and thus reduce 00805 * the image data transfer rate) than sacrifice redundancy completely 00806 */ 00807 for ( ; 00808 (new_max < 80) && (udptl->error_correction_entries > 1); 00809 --udptl->error_correction_entries) { 00810 new_max = (udptl->far_max_datagram - 8) / (udptl->error_correction_entries + 1); 00811 } 00812 break; 00813 case UDPTL_ERROR_CORRECTION_FEC: 00814 /* need room for sequence number, length indicators and a 00815 * a single IFP of the maximum size expected 00816 */ 00817 new_max = (udptl->far_max_datagram - 10) / 2; 00818 break; 00819 } 00820 /* subtract 5% of space for insurance */ 00821 udptl->far_max_ifp = new_max * 0.95; 00822 }
| static void calculate_local_max_datagram | ( | struct ast_udptl * | udptl | ) | [static] |
Definition at line 722 of file udptl.c.
References ast_log(), ast_udptl::error_correction_scheme, LOCAL_FAX_MAX_DATAGRAM, ast_udptl::local_max_datagram, ast_udptl::local_max_ifp, LOG_TAG, LOG_WARNING, MIN, UDPTL_ERROR_CORRECTION_FEC, UDPTL_ERROR_CORRECTION_NONE, and UDPTL_ERROR_CORRECTION_REDUNDANCY.
Referenced by ast_udptl_get_local_max_datagram().
00723 { 00724 unsigned int new_max = 0; 00725 00726 if (udptl->local_max_ifp == -1) { 00727 ast_log(LOG_WARNING, "(%s): Cannot calculate local_max_datagram before local_max_ifp has been set.\n", 00728 LOG_TAG(udptl)); 00729 udptl->local_max_datagram = -1; 00730 return; 00731 } 00732 00733 /* calculate the amount of space required to receive an IFP 00734 * of the maximum size supported by the application/endpoint 00735 * that we are delivering them to (local endpoint), and add 00736 * the amount of space required to support the selected 00737 * error correction mode 00738 */ 00739 switch (udptl->error_correction_scheme) { 00740 case UDPTL_ERROR_CORRECTION_NONE: 00741 /* need room for sequence number, length indicator, redundancy 00742 * indicator and following length indicator 00743 */ 00744 new_max = 5 + udptl->local_max_ifp; 00745 break; 00746 case UDPTL_ERROR_CORRECTION_REDUNDANCY: 00747 /* need room for sequence number, length indicators, plus 00748 * room for up to 3 redundancy packets 00749 */ 00750 new_max = 5 + udptl->local_max_ifp + 2 + (3 * udptl->local_max_ifp); 00751 break; 00752 case UDPTL_ERROR_CORRECTION_FEC: 00753 /* need room for sequence number, length indicators and a 00754 * a single IFP of the maximum size expected 00755 */ 00756 new_max = 5 + udptl->local_max_ifp + 4 + udptl->local_max_ifp; 00757 break; 00758 } 00759 /* add 5% extra space for insurance, but no larger than LOCAL_FAX_MAX_DATAGRAM */ 00760 udptl->local_max_datagram = MIN(new_max * 1.05, LOCAL_FAX_MAX_DATAGRAM); 00761 }
| static int decode_length | ( | uint8_t * | buf, | |
| unsigned int | limit, | |||
| unsigned int * | len, | |||
| unsigned int * | pvalue | |||
| ) | [static] |
Definition at line 200 of file udptl.c.
Referenced by decode_open_type(), and udptl_rx_packet().
00201 { 00202 if (*len >= limit) 00203 return -1; 00204 if ((buf[*len] & 0x80) == 0) { 00205 *pvalue = buf[*len]; 00206 (*len)++; 00207 return 0; 00208 } 00209 if ((buf[*len] & 0x40) == 0) { 00210 if (*len == limit - 1) 00211 return -1; 00212 *pvalue = (buf[*len] & 0x3F) << 8; 00213 (*len)++; 00214 *pvalue |= buf[*len]; 00215 (*len)++; 00216 return 0; 00217 } 00218 *pvalue = (buf[*len] & 0x3F) << 14; 00219 (*len)++; 00220 /* Indicate we have a fragment */ 00221 return 1; 00222 }
| static int decode_open_type | ( | uint8_t * | buf, | |
| unsigned int | limit, | |||
| unsigned int * | len, | |||
| const uint8_t ** | p_object, | |||
| unsigned int * | p_num_octets | |||
| ) | [static] |
Definition at line 225 of file udptl.c.
References decode_length().
Referenced by udptl_rx_packet().
00226 { 00227 unsigned int octet_cnt; 00228 unsigned int octet_idx; 00229 unsigned int length; 00230 unsigned int i; 00231 const uint8_t **pbuf; 00232 00233 for (octet_idx = 0, *p_num_octets = 0; ; octet_idx += octet_cnt) { 00234 octet_cnt = 0; 00235 if ((length = decode_length(buf, limit, len, &octet_cnt)) < 0) 00236 return -1; 00237 if (octet_cnt > 0) { 00238 *p_num_octets += octet_cnt; 00239 00240 pbuf = &p_object[octet_idx]; 00241 i = 0; 00242 /* Make sure the buffer contains at least the number of bits requested */ 00243 if ((*len + octet_cnt) > limit) 00244 return -1; 00245 00246 *pbuf = &buf[*len]; 00247 *len += octet_cnt; 00248 } 00249 if (length == 0) 00250 break; 00251 } 00252 return 0; 00253 }
| static unsigned int encode_length | ( | uint8_t * | buf, | |
| unsigned int * | len, | |||
| unsigned int | value | |||
| ) | [static] |
Definition at line 256 of file udptl.c.
Referenced by encode_open_type(), and udptl_build_packet().
00257 { 00258 unsigned int multiplier; 00259 00260 if (value < 0x80) { 00261 /* 1 octet */ 00262 buf[*len] = value; 00263 (*len)++; 00264 return value; 00265 } 00266 if (value < 0x4000) { 00267 /* 2 octets */ 00268 /* Set the first bit of the first octet */ 00269 buf[*len] = ((0x8000 | value) >> 8) & 0xFF; 00270 (*len)++; 00271 buf[*len] = value & 0xFF; 00272 (*len)++; 00273 return value; 00274 } 00275 /* Fragmentation */ 00276 multiplier = (value < 0x10000) ? (value >> 14) : 4; 00277 /* Set the first 2 bits of the octet */ 00278 buf[*len] = 0xC0 | multiplier; 00279 (*len)++; 00280 return multiplier << 14; 00281 }
| static int encode_open_type | ( | const struct ast_udptl * | udptl, | |
| uint8_t * | buf, | |||
| unsigned int | buflen, | |||
| unsigned int * | len, | |||
| const uint8_t * | data, | |||
| unsigned int | num_octets | |||
| ) | [static] |
Definition at line 284 of file udptl.c.
References ast_log(), encode_length(), LOG_ERROR, and LOG_TAG.
Referenced by udptl_build_packet().
00286 { 00287 unsigned int enclen; 00288 unsigned int octet_idx; 00289 uint8_t zero_byte; 00290 00291 /* If open type is of zero length, add a single zero byte (10.1) */ 00292 if (num_octets == 0) { 00293 zero_byte = 0; 00294 data = &zero_byte; 00295 num_octets = 1; 00296 } 00297 /* Encode the open type */ 00298 for (octet_idx = 0; ; num_octets -= enclen, octet_idx += enclen) { 00299 if ((enclen = encode_length(buf, len, num_octets)) < 0) 00300 return -1; 00301 if (enclen + *len > buflen) { 00302 ast_log(LOG_ERROR, "(%s): Buffer overflow detected (%d + %d > %d)\n", 00303 LOG_TAG(udptl), enclen, *len, buflen); 00304 return -1; 00305 } 00306 if (enclen > 0) { 00307 memcpy(&buf[*len], &data[octet_idx], enclen); 00308 *len += enclen; 00309 } 00310 if (enclen >= num_octets) 00311 break; 00312 } 00313 00314 return 0; 00315 }
| static struct ast_udptl_protocol* get_proto | ( | struct ast_channel * | chan | ) | [static, read] |
Definition at line 1129 of file udptl.c.
References AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, ast_udptl_protocol::list, ast_channel::tech, ast_channel_tech::type, and ast_udptl_protocol::type.
Referenced by ast_udptl_bridge().
01130 { 01131 struct ast_udptl_protocol *cur = NULL; 01132 01133 AST_RWLIST_RDLOCK(&protos); 01134 AST_RWLIST_TRAVERSE(&protos, cur, list) { 01135 if (cur->type == chan->tech->type) 01136 break; 01137 } 01138 AST_RWLIST_UNLOCK(&protos); 01139 01140 return cur; 01141 }
| static char* handle_cli_udptl_debug_deprecated | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 1268 of file udptl.c.
References ast_cli_args::argc, ast_cli_args::argv, ast_cli(), ast_gethostbyname(), ast_inet_ntoa(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, hp, udptldebugaddr, and ast_cli_entry::usage.
01269 { 01270 struct hostent *hp; 01271 struct ast_hostent ahp; 01272 int port; 01273 char *p; 01274 char *arg; 01275 01276 switch (cmd) { 01277 case CLI_INIT: 01278 e->command = "udptl debug [off|ip]"; 01279 e->usage = 01280 "Usage: udptl debug [off]|[ip host[:port]]\n" 01281 " Enable or disable dumping of UDPTL packets.\n" 01282 " If ip is specified, limit the dumped packets to those to and from\n" 01283 " the specified 'host' with optional port.\n"; 01284 return NULL; 01285 case CLI_GENERATE: 01286 return NULL; 01287 } 01288 01289 if (a->argc < 2 || a->argc > 4) 01290 return CLI_SHOWUSAGE; 01291 01292 if (a->argc == 2) { 01293 udptldebug = 1; 01294 memset(&udptldebugaddr, 0, sizeof(udptldebugaddr)); 01295 ast_cli(a->fd, "UDPTL Debugging Enabled\n"); 01296 } else if (a->argc == 3) { 01297 if (strncasecmp(a->argv[2], "off", 3)) 01298 return CLI_SHOWUSAGE; 01299 udptldebug = 0; 01300 ast_cli(a->fd, "UDPTL Debugging Disabled\n"); 01301 } else { 01302 if (strncasecmp(a->argv[2], "ip", 2)) 01303 return CLI_SHOWUSAGE; 01304 port = 0; 01305 arg = a->argv[3]; 01306 p = strstr(arg, ":"); 01307 if (p) { 01308 *p = '\0'; 01309 p++; 01310 port = atoi(p); 01311 } 01312 hp = ast_gethostbyname(arg, &ahp); 01313 if (hp == NULL) 01314 return CLI_SHOWUSAGE; 01315 udptldebugaddr.sin_family = AF_INET; 01316 memcpy(&udptldebugaddr.sin_addr, hp->h_addr, sizeof(udptldebugaddr.sin_addr)); 01317 udptldebugaddr.sin_port = htons(port); 01318 if (port == 0) 01319 ast_cli(a->fd, "UDPTL Debugging Enabled for IP: %s\n", ast_inet_ntoa(udptldebugaddr.sin_addr)); 01320 else 01321 ast_cli(a->fd, "UDPTL Debugging Enabled for IP: %s:%d\n", ast_inet_ntoa(udptldebugaddr.sin_addr), port); 01322 udptldebug = 1; 01323 } 01324 01325 return CLI_SUCCESS; 01326 }
| static char* handle_cli_udptl_set_debug | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 1328 of file udptl.c.
References ast_cli_args::argc, ast_cli_args::argv, ast_cli(), ast_gethostbyname(), ast_inet_ntoa(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, hp, udptldebugaddr, and ast_cli_entry::usage.
01329 { 01330 struct hostent *hp; 01331 struct ast_hostent ahp; 01332 int port; 01333 char *p; 01334 char *arg; 01335 01336 switch (cmd) { 01337 case CLI_INIT: 01338 e->command = "udptl set debug {on|off|ip}"; 01339 e->usage = 01340 "Usage: udptl set debug {on|off|ip host[:port]}\n" 01341 " Enable or disable dumping of UDPTL packets.\n" 01342 " If ip is specified, limit the dumped packets to those to and from\n" 01343 " the specified 'host' with optional port.\n"; 01344 return NULL; 01345 case CLI_GENERATE: 01346 return NULL; 01347 } 01348 01349 if (a->argc < 4 || a->argc > 5) 01350 return CLI_SHOWUSAGE; 01351 01352 if (a->argc == 4) { 01353 if (!strncasecmp(a->argv[3], "on", 2)) { 01354 udptldebug = 1; 01355 memset(&udptldebugaddr, 0, sizeof(udptldebugaddr)); 01356 ast_cli(a->fd, "UDPTL Debugging Enabled\n"); 01357 } else if (!strncasecmp(a->argv[3], "off", 3)) { 01358 udptldebug = 0; 01359 ast_cli(a->fd, "UDPTL Debugging Disabled\n"); 01360 } else { 01361 return CLI_SHOWUSAGE; 01362 } 01363 } else { 01364 if (strncasecmp(a->argv[3], "ip", 2)) 01365 return CLI_SHOWUSAGE; 01366 port = 0; 01367 arg = a->argv[4]; 01368 p = strstr(arg, ":"); 01369 if (p) { 01370 *p = '\0'; 01371 p++; 01372 port = atoi(p); 01373 } 01374 hp = ast_gethostbyname(arg, &ahp); 01375 if (hp == NULL) 01376 return CLI_SHOWUSAGE; 01377 udptldebugaddr.sin_family = AF_INET; 01378 memcpy(&udptldebugaddr.sin_addr, hp->h_addr, sizeof(udptldebugaddr.sin_addr)); 01379 udptldebugaddr.sin_port = htons(port); 01380 if (port == 0) 01381 ast_cli(a->fd, "UDPTL Debugging Enabled for IP: %s\n", ast_inet_ntoa(udptldebugaddr.sin_addr)); 01382 else 01383 ast_cli(a->fd, "UDPTL Debugging Enabled for IP: %s:%d\n", ast_inet_ntoa(udptldebugaddr.sin_addr), port); 01384 udptldebug = 1; 01385 } 01386 01387 return CLI_SUCCESS; 01388 }
| static int udptl_build_packet | ( | struct ast_udptl * | s, | |
| uint8_t * | buf, | |||
| unsigned int | buflen, | |||
| uint8_t * | ifp, | |||
| unsigned int | ifp_len | |||
| ) | [static] |
Definition at line 526 of file udptl.c.
References ast_debug, udptl_fec_tx_buffer_t::buf, udptl_fec_tx_buffer_t::buf_len, encode_length(), encode_open_type(), ast_udptl::error_correction_entries, ast_udptl::error_correction_scheme, ast_udptl::error_correction_span, len(), LOCAL_FAX_MAX_DATAGRAM, LOG_TAG, seq, ast_udptl::tx, ast_udptl::tx_seq_no, UDPTL_BUF_MASK, UDPTL_ERROR_CORRECTION_FEC, UDPTL_ERROR_CORRECTION_NONE, UDPTL_ERROR_CORRECTION_REDUNDANCY, and ast_udptl::verbose.
Referenced by ast_udptl_write().
00527 { 00528 uint8_t fec[LOCAL_FAX_MAX_DATAGRAM * 2]; 00529 int i; 00530 int j; 00531 int seq; 00532 int entry; 00533 int entries; 00534 int span; 00535 int m; 00536 unsigned int len; 00537 int limit; 00538 int high_tide; 00539 00540 seq = s->tx_seq_no & 0xFFFF; 00541 00542 /* Map the sequence number to an entry in the circular buffer */ 00543 entry = seq & UDPTL_BUF_MASK; 00544 00545 /* We save the message in a circular buffer, for generating FEC or 00546 redundancy sets later on. */ 00547 s->tx[entry].buf_len = ifp_len; 00548 memcpy(s->tx[entry].buf, ifp, ifp_len); 00549 00550 /* Build the UDPTLPacket */ 00551 00552 len = 0; 00553 /* Encode the sequence number */ 00554 buf[len++] = (seq >> 8) & 0xFF; 00555 buf[len++] = seq & 0xFF; 00556 00557 /* Encode the primary IFP packet */ 00558 if (encode_open_type(s, buf, buflen, &len, ifp, ifp_len) < 0) 00559 return -1; 00560 00561 /* Encode the appropriate type of error recovery information */ 00562 switch (s->error_correction_scheme) 00563 { 00564 case UDPTL_ERROR_CORRECTION_NONE: 00565 /* Encode the error recovery type */ 00566 buf[len++] = 0x00; 00567 /* The number of entries will always be zero, so it is pointless allowing 00568 for the fragmented case here. */ 00569 if (encode_length(buf, &len, 0) < 0) 00570 return -1; 00571 break; 00572 case UDPTL_ERROR_CORRECTION_REDUNDANCY: 00573 /* Encode the error recovery type */ 00574 buf[len++] = 0x00; 00575 if (s->tx_seq_no > s->error_correction_entries) 00576 entries = s->error_correction_entries; 00577 else 00578 entries = s->tx_seq_no; 00579 /* The number of entries will always be small, so it is pointless allowing 00580 for the fragmented case here. */ 00581 if (encode_length(buf, &len, entries) < 0) 00582 return -1; 00583 /* Encode the elements */ 00584 for (i = 0; i < entries; i++) { 00585 j = (entry - i - 1) & UDPTL_BUF_MASK; 00586 if (encode_open_type(s, buf, buflen, &len, s->tx[j].buf, s->tx[j].buf_len) < 0) { 00587 ast_debug(1, "(%s): Encoding failed at i=%d, j=%d\n", 00588 LOG_TAG(s), i, j); 00589 return -1; 00590 } 00591 } 00592 break; 00593 case UDPTL_ERROR_CORRECTION_FEC: 00594 span = s->error_correction_span; 00595 entries = s->error_correction_entries; 00596 if (seq < s->error_correction_span*s->error_correction_entries) { 00597 /* In the initial stages, wind up the FEC smoothly */ 00598 entries = seq/s->error_correction_span; 00599 if (seq < s->error_correction_span) 00600 span = 0; 00601 } 00602 /* Encode the error recovery type */ 00603 buf[len++] = 0x80; 00604 /* Span is defined as an inconstrained integer, which it dumb. It will only 00605 ever be a small value. Treat it as such. */ 00606 buf[len++] = 1; 00607 buf[len++] = span; 00608 /* The number of entries is defined as a length, but will only ever be a small 00609 value. Treat it as such. */ 00610 buf[len++] = entries; 00611 for (m = 0; m < entries; m++) { 00612 /* Make an XOR'ed entry the maximum length */ 00613 limit = (entry + m) & UDPTL_BUF_MASK; 00614 high_tide = 0; 00615 for (i = (limit - span*entries) & UDPTL_BUF_MASK; i != limit; i = (i + entries) & UDPTL_BUF_MASK) { 00616 if (high_tide < s->tx[i].buf_len) { 00617 for (j = 0; j < high_tide; j++) 00618 fec[j] ^= s->tx[i].buf[j]; 00619 for ( ; j < s->tx[i].buf_len; j++) 00620 fec[j] = s->tx[i].buf[j]; 00621 high_tide = s->tx[i].buf_len; 00622 } else { 00623 for (j = 0; j < s->tx[i].buf_len; j++) 00624 fec[j] ^= s->tx[i].buf[j]; 00625 } 00626 } 00627 if (encode_open_type(s, buf, buflen, &len, fec, high_tide) < 0) 00628 return -1; 00629 } 00630 break; 00631 } 00632 00633 if (s->verbose) 00634 fprintf(stderr, "\n"); 00635 00636 s->tx_seq_no++; 00637 return len; 00638 }
| static int udptl_debug_test_addr | ( | const struct sockaddr_in * | addr | ) | [inline, static] |
Definition at line 187 of file udptl.c.
References udptldebugaddr.
Referenced by ast_udptl_read(), and ast_udptl_write().
00188 { 00189 if (udptldebug == 0) 00190 return 0; 00191 if (udptldebugaddr.sin_addr.s_addr) { 00192 if (((ntohs(udptldebugaddr.sin_port) != 0) && 00193 (udptldebugaddr.sin_port != addr->sin_port)) || 00194 (udptldebugaddr.sin_addr.s_addr != addr->sin_addr.s_addr)) 00195 return 0; 00196 } 00197 return 1; 00198 }
| static int udptl_rx_packet | ( | struct ast_udptl * | s, | |
| uint8_t * | buf, | |||
| unsigned int | len | |||
| ) | [static] |
Definition at line 318 of file udptl.c.
References AST_FRAME_MODEM, AST_LIST_NEXT, AST_MODEM_T38, udptl_fec_rx_buffer_t::buf, udptl_fec_rx_buffer_t::buf_len, ast_frame::data, ast_frame::datalen, decode_length(), decode_open_type(), ast_udptl::f, udptl_fec_rx_buffer_t::fec, udptl_fec_rx_buffer_t::fec_entries, udptl_fec_rx_buffer_t::fec_len, udptl_fec_rx_buffer_t::fec_span, ast_frame::frametype, LOCAL_FAX_MAX_DATAGRAM, ast_frame::mallocd, ast_frame::offset, ast_frame::ptr, ast_udptl::rx, ast_udptl::rx_seq_no, ast_frame::seqno, ast_frame::src, ast_frame::subclass, TRUE, and UDPTL_BUF_MASK.
Referenced by ast_udptl_read().
00319 { 00320 int stat1; 00321 int stat2; 00322 int i; 00323 int j; 00324 int k; 00325 int l; 00326 int m; 00327 int x; 00328 int limit; 00329 int which; 00330 unsigned int ptr; 00331 unsigned int count; 00332 int total_count; 00333 int seq_no; 00334 const uint8_t *ifp; 00335 const uint8_t *data; 00336 unsigned int ifp_len; 00337 int repaired[16]; 00338 const uint8_t *bufs[16]; 00339 unsigned int lengths[16]; 00340 int span; 00341 int entries; 00342 int ifp_no; 00343 00344 ptr = 0; 00345 ifp_no = 0; 00346 memset(&s->f[0], 0, sizeof(s->f[0])); 00347 00348 /* Decode seq_number */ 00349 if (ptr + 2 > len) 00350 return -1; 00351 seq_no = (buf[0] << 8) | buf[1]; 00352 ptr += 2; 00353 00354 /* Break out the primary packet */ 00355 if ((stat1 = decode_open_type(buf, len, &ptr, &ifp, &ifp_len)) != 0) 00356 return -1; 00357 /* Decode error_recovery */ 00358 if (ptr + 1 > len) 00359 return -1; 00360 if ((buf[ptr++] & 0x80) == 0) { 00361 /* Secondary packet mode for error recovery */ 00362 if (seq_no > s->rx_seq_no) { 00363 /* We received a later packet than we expected, so we need to check if we can fill in the gap from the 00364 secondary packets. */ 00365 total_count = 0; 00366 do { 00367 if ((stat2 = decode_length(buf, len, &ptr, &count)) < 0) 00368 return -1; 00369 for (i = 0; i < count; i++) { 00370 if ((stat1 = decode_open_type(buf, len, &ptr, &bufs[total_count + i], &lengths[total_count + i])) != 0) 00371 return -1; 00372 } 00373 total_count += count; 00374 } 00375 while (stat2 > 0); 00376 /* Step through in reverse order, so we go oldest to newest */ 00377 for (i = total_count; i > 0; i--) { 00378 if (seq_no - i >= s->rx_seq_no) { 00379 /* This one wasn't seen before */ 00380 /* Decode the secondary IFP packet */ 00381 //fprintf(stderr, "Secondary %d, len %d\n", seq_no - i, lengths[i - 1]); 00382 s->f[ifp_no].frametype = AST_FRAME_MODEM; 00383 s->f[ifp_no].subclass = AST_MODEM_T38; 00384 00385 s->f[ifp_no].mallocd = 0; 00386 s->f[ifp_no].seqno = seq_no - i; 00387 s->f[ifp_no].datalen = lengths[i - 1]; 00388 s->f[ifp_no].data.ptr = (uint8_t *) bufs[i - 1]; 00389 s->f[ifp_no].offset = 0; 00390 s->f[ifp_no].src = "UDPTL"; 00391 if (ifp_no > 0) 00392 AST_LIST_NEXT(&s->f[ifp_no - 1], frame_list) = &s->f[ifp_no]; 00393 AST_LIST_NEXT(&s->f[ifp_no], frame_list) = NULL; 00394 ifp_no++; 00395 } 00396 } 00397 } 00398 } 00399 else 00400 { 00401 /* FEC mode for error recovery */ 00402 /* Our buffers cannot tolerate overlength IFP packets in FEC mode */ 00403 if (ifp_len > LOCAL_FAX_MAX_DATAGRAM) 00404 return -1; 00405 /* Update any missed slots in the buffer */ 00406 for ( ; seq_no > s->rx_seq_no; s->rx_seq_no++) { 00407 x = s->rx_seq_no & UDPTL_BUF_MASK; 00408 s->rx[x].buf_len = -1; 00409 s->rx[x].fec_len[0] = 0; 00410 s->rx[x].fec_span = 0; 00411 s->rx[x].fec_entries = 0; 00412 } 00413 00414 x = seq_no & UDPTL_BUF_MASK; 00415 00416 memset(repaired, 0, sizeof(repaired)); 00417 00418 /* Save the new IFP packet */ 00419 memcpy(s->rx[x].buf, ifp, ifp_len); 00420 s->rx[x].buf_len = ifp_len; 00421 repaired[x] = TRUE; 00422 00423 /* Decode the FEC packets */ 00424 /* The span is defined as an unconstrained integer, but will never be more 00425 than a small value. */ 00426 if (ptr + 2 > len) 00427 return -1; 00428 if (buf[ptr++] != 1) 00429 return -1; 00430 span = buf[ptr++]; 00431 s->rx[x].fec_span = span; 00432 00433 /* The number of entries is defined as a length, but will only ever be a small 00434 value. Treat it as such. */ 00435 if (ptr + 1 > len) 00436 return -1; 00437 entries = buf[ptr++]; 00438 s->rx[x].fec_entries = entries; 00439 00440 /* Decode the elements */ 00441 for (i = 0; i < entries; i++) { 00442 if ((stat1 = decode_open_type(buf, len, &ptr, &data, &s->rx[x].fec_len[i])) != 0) 00443 return -1; 00444 if (s->rx[x].fec_len[i] > LOCAL_FAX_MAX_DATAGRAM) 00445 return -1; 00446 00447 /* Save the new FEC data */ 00448 memcpy(s->rx[x].fec[i], data, s->rx[x].fec_len[i]); 00449 #if 0 00450 fprintf(stderr, "FEC: "); 00451 for (j = 0; j < s->rx[x].fec_len[i]; j++) 00452 fprintf(stderr, "%02X ", data[j]); 00453 fprintf(stderr, "\n"); 00454 #endif 00455 } 00456 00457 /* See if we can reconstruct anything which is missing */ 00458 /* TODO: this does not comprehensively hunt back and repair everything that is possible */ 00459 for (l = x; l != ((x - (16 - span*entries)) & UDPTL_BUF_MASK); l = (l - 1) & UDPTL_BUF_MASK) { 00460 if (s->rx[l].fec_len[0] <= 0) 00461 continue; 00462 for (m = 0; m < s->rx[l].fec_entries; m++) { 00463 limit = (l + m) & UDPTL_BUF_MASK; 00464 for (which = -1, k = (limit - s->rx[l].fec_span * s->rx[l].fec_entries) & UDPTL_BUF_MASK; k != limit; k = (k + s->rx[l].fec_entries) & UDPTL_BUF_MASK) { 00465 if (s->rx[k].buf_len <= 0) 00466 which = (which == -1) ? k : -2; 00467 } 00468 if (which >= 0) { 00469 /* Repairable */ 00470 for (j = 0; j < s->rx[l].fec_len[m]; j++) { 00471 s->rx[which].buf[j] = s->rx[l].fec[m][j]; 00472 for (k = (limit - s->rx[l].fec_span * s->rx[l].fec_entries) & UDPTL_BUF_MASK; k != limit; k = (k + s->rx[l].fec_entries) & UDPTL_BUF_MASK) 00473 s->rx[which].buf[j] ^= (s->rx[k].buf_len > j) ? s->rx[k].buf[j] : 0; 00474 } 00475 s->rx[which].buf_len = s->rx[l].fec_len[m]; 00476 repaired[which] = TRUE; 00477 } 00478 } 00479 } 00480 /* Now play any new packets forwards in time */ 00481 for (l = (x + 1) & UDPTL_BUF_MASK, j = seq_no - UDPTL_BUF_MASK; l != x; l = (l + 1) & UDPTL_BUF_MASK, j++) { 00482 if (repaired[l]) { 00483 //fprintf(stderr, "Fixed packet %d, len %d\n", j, l); 00484 s->f[ifp_no].frametype = AST_FRAME_MODEM; 00485 s->f[ifp_no].subclass = AST_MODEM_T38; 00486 00487 s->f[ifp_no].mallocd = 0; 00488 s->f[ifp_no].seqno = j; 00489 s->f[ifp_no].datalen = s->rx[l].buf_len; 00490 s->f[ifp_no].data.ptr = s->rx[l].buf; 00491 s->f[ifp_no].offset = 0; 00492 s->f[ifp_no].src = "UDPTL"; 00493 if (ifp_no > 0) 00494 AST_LIST_NEXT(&s->f[ifp_no - 1], frame_list) = &s->f[ifp_no]; 00495 AST_LIST_NEXT(&s->f[ifp_no], frame_list) = NULL; 00496 ifp_no++; 00497 } 00498 } 00499 } 00500 00501 /* If packets are received out of sequence, we may have already processed this packet from the error 00502 recovery information in a packet already received. */ 00503 if (seq_no >= s->rx_seq_no) { 00504 /* Decode the primary IFP packet */ 00505 s->f[ifp_no].frametype = AST_FRAME_MODEM; 00506 s->f[ifp_no].subclass = AST_MODEM_T38; 00507 00508 s->f[ifp_no].mallocd = 0; 00509 s->f[ifp_no].seqno = seq_no; 00510 s->f[ifp_no].datalen = ifp_len; 00511 s->f[ifp_no].data.ptr = (uint8_t *) ifp; 00512 s->f[ifp_no].offset = 0; 00513 s->f[ifp_no].src = "UDPTL"; 00514 if (ifp_no > 0) 00515 AST_LIST_NEXT(&s->f[ifp_no - 1], frame_list) = &s->f[ifp_no]; 00516 AST_LIST_NEXT(&s->f[ifp_no], frame_list) = NULL; 00517 00518 ifp_no++; 00519 } 00520 00521 s->rx_seq_no = seq_no + 1; 00522 return ifp_no; 00523 }
| static int udptlread | ( | int * | id, | |
| int | fd, | |||
| short | events, | |||
| void * | cbdata | |||
| ) | [static] |
Definition at line 660 of file udptl.c.
References ast_udptl_read(), ast_udptl::callback, ast_udptl::data, and f.
Referenced by ast_udptl_new_with_bindaddr().
struct ast_cli_entry cli_handle_udptl_debug_deprecated = AST_CLI_DEFINE(handle_cli_udptl_debug_deprecated, "Enable/Disable UDPTL debugging") [static] |
struct ast_cli_entry cli_udptl[] [static] |
int udptldebug [static] |
struct sockaddr_in udptldebugaddr [static] |
Debug packets to/from this host
Definition at line 85 of file udptl.c.
Referenced by handle_cli_udptl_debug_deprecated(), handle_cli_udptl_set_debug(), and udptl_debug_test_addr().
int udptlfecentries [static] |
int udptlfecspan [static] |
int udptlstart = 4500 [static] |
int use_even_ports [static] |
1.6.1