2
0

udptl.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655
  1. //#define UDPTL_DEBUG
  2. /*
  3. * SpanDSP - a series of DSP components for telephony
  4. *
  5. * udptl.c - An implementation of the UDPTL protocol defined in T.38,
  6. * less the packet exchange part
  7. *
  8. * Written by Steve Underwood <steveu@coppice.org>
  9. *
  10. * Copyright (C) 2005, 2009, 2012 Steve Underwood
  11. *
  12. * All rights reserved.
  13. *
  14. * This program is free software; you can redistribute it and/or modify
  15. * it under the terms of the GNU General Public License version 2, as
  16. * published by the Free Software Foundation.
  17. *
  18. * This program is distributed in the hope that it will be useful,
  19. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  20. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  21. * GNU General Public License for more details.
  22. *
  23. * You should have received a copy of the GNU General Public License
  24. * along with this program; if not, write to the Free Software
  25. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  26. */
  27. #if defined(HAVE_CONFIG_H)
  28. #include "config.h"
  29. #endif
  30. #include <stdio.h>
  31. #include <stdlib.h>
  32. #include <sys/types.h>
  33. #include <inttypes.h>
  34. #include <memory.h>
  35. #if defined(HAVE_STDBOOL_H)
  36. #include <stdbool.h>
  37. #else
  38. #include <spandsp/stdbool.h>
  39. #endif
  40. #include "udptl.h"
  41. static int decode_length(const uint8_t *buf, int limit, int *len, int *pvalue)
  42. {
  43. if (*len >= limit)
  44. return -1;
  45. if ((buf[*len] & 0x80) == 0)
  46. {
  47. *pvalue = buf[(*len)++];
  48. return 0;
  49. }
  50. if ((buf[*len] & 0x40) == 0)
  51. {
  52. if (*len >= limit - 1)
  53. return -1;
  54. *pvalue = (buf[(*len)++] & 0x3F) << 8;
  55. *pvalue |= buf[(*len)++];
  56. return 0;
  57. }
  58. *pvalue = (buf[(*len)++] & 0x3F) << 14;
  59. /* Indicate that we have a fragment */
  60. return 1;
  61. }
  62. /*- End of function --------------------------------------------------------*/
  63. static int decode_open_type(const uint8_t *buf, int limit, int *len, const uint8_t **p_object, int *p_num_octets)
  64. {
  65. int octet_cnt;
  66. #if 0
  67. int octet_idx;
  68. int stat;
  69. const uint8_t **pbuf;
  70. *p_num_octets = 0;
  71. for (octet_idx = 0; ; octet_idx += octet_cnt)
  72. {
  73. if ((stat = decode_length(buf, limit, len, &octet_cnt)) < 0)
  74. return -1;
  75. if (octet_cnt > 0)
  76. {
  77. *p_num_octets += octet_cnt;
  78. pbuf = &p_object[octet_idx];
  79. /* Make sure the buffer contains at least the number of bits requested */
  80. if ((*len + octet_cnt) > limit)
  81. return -1;
  82. *pbuf = &buf[*len];
  83. *len += octet_cnt;
  84. }
  85. if (stat == 0)
  86. break;
  87. }
  88. #else
  89. /* We do not deal with fragments, so there is no point in looping through them. Just say that something
  90. fragmented is bad. */
  91. if (decode_length(buf, limit, len, &octet_cnt) != 0)
  92. return -1;
  93. *p_num_octets = octet_cnt;
  94. if (octet_cnt > 0)
  95. {
  96. /* Make sure the buffer contains at least the number of bits requested */
  97. if ((*len + octet_cnt) > limit)
  98. return -1;
  99. *p_object = &buf[*len];
  100. *len += octet_cnt;
  101. }
  102. #endif
  103. return 0;
  104. }
  105. /*- End of function --------------------------------------------------------*/
  106. static int encode_length(uint8_t *buf, int *len, int value)
  107. {
  108. int multiplier;
  109. if (value < 0x80)
  110. {
  111. /* 1 octet */
  112. buf[(*len)++] = value;
  113. return value;
  114. }
  115. if (value < 0x4000)
  116. {
  117. /* 2 octets */
  118. /* Set the first bit of the first octet */
  119. buf[(*len)++] = ((0x8000 | value) >> 8) & 0xFF;
  120. buf[(*len)++] = value & 0xFF;
  121. return value;
  122. }
  123. /* Fragmentation */
  124. multiplier = (value < 0x10000) ? (value >> 14) : 4;
  125. /* Set the first 2 bits of the octet */
  126. buf[(*len)++] = 0xC0 | multiplier;
  127. return multiplier << 14;
  128. }
  129. /*- End of function --------------------------------------------------------*/
  130. static int encode_open_type(uint8_t *buf, int *len, const uint8_t *data, int num_octets)
  131. {
  132. int enclen;
  133. int octet_idx;
  134. uint8_t zero_byte;
  135. /* If open type is of zero length, add a single zero byte (10.1) */
  136. if (num_octets == 0)
  137. {
  138. zero_byte = 0;
  139. data = &zero_byte;
  140. num_octets = 1;
  141. }
  142. /* Encode the open type */
  143. for (octet_idx = 0; ; num_octets -= enclen, octet_idx += enclen)
  144. {
  145. if ((enclen = encode_length(buf, len, num_octets)) < 0)
  146. return -1;
  147. if (enclen > 0)
  148. {
  149. memcpy(&buf[*len], &data[octet_idx], enclen);
  150. *len += enclen;
  151. }
  152. if (enclen >= num_octets)
  153. break;
  154. }
  155. return 0;
  156. }
  157. /*- End of function --------------------------------------------------------*/
  158. int udptl_rx_packet(udptl_state_t *s, const uint8_t buf[], int len)
  159. {
  160. int stat;
  161. int i;
  162. int j;
  163. int k;
  164. int l;
  165. int m;
  166. int x;
  167. int limit;
  168. int which;
  169. int ptr;
  170. int count;
  171. int total_count;
  172. int seq_no;
  173. const uint8_t *msg;
  174. const uint8_t *data;
  175. int msg_len;
  176. int repaired[16];
  177. const uint8_t *bufs[16];
  178. int lengths[16];
  179. int span;
  180. int entries;
  181. ptr = 0;
  182. /* Decode seq_number */
  183. if (ptr + 2 > len)
  184. return -1;
  185. seq_no = (buf[0] << 8) | buf[1];
  186. ptr += 2;
  187. /* Break out the primary packet */
  188. if ((stat = decode_open_type(buf, len, &ptr, &msg, &msg_len)) != 0)
  189. return -1;
  190. /* Decode error_recovery */
  191. if (ptr + 1 > len)
  192. return -1;
  193. /* Our buffers cannot tolerate overlength packets */
  194. if (msg_len > LOCAL_FAX_MAX_DATAGRAM)
  195. return -1;
  196. /* Update any missed slots in the buffer */
  197. for (i = s->rx_seq_no; seq_no > i; i++)
  198. {
  199. x = i & UDPTL_BUF_MASK;
  200. s->rx[x].buf_len = -1;
  201. s->rx[x].fec_len[0] = 0;
  202. s->rx[x].fec_span = 0;
  203. s->rx[x].fec_entries = 0;
  204. }
  205. /* Save the new packet. Pure redundancy mode won't use this, but some systems will switch
  206. into FEC mode after sending some redundant packets. */
  207. x = seq_no & UDPTL_BUF_MASK;
  208. if (msg_len > 0)
  209. memcpy(s->rx[x].buf, msg, msg_len);
  210. s->rx[x].buf_len = msg_len;
  211. s->rx[x].fec_len[0] = 0;
  212. s->rx[x].fec_span = 0;
  213. s->rx[x].fec_entries = 0;
  214. if ((buf[ptr++] & 0x80) == 0)
  215. {
  216. /* Secondary packet mode for error recovery */
  217. /* We might have the packet we want, but we need to check through
  218. the redundant stuff, and verify the integrity of the UDPTL.
  219. This greatly reduces our chances of accepting garbage. */
  220. total_count = 0;
  221. do
  222. {
  223. if ((stat = decode_length(buf, len, &ptr, &count)) < 0)
  224. return -1;
  225. if ((total_count + count) >= 16)
  226. {
  227. /* There is too much stuff here to be real, and it would overflow the bufs array
  228. if we continue */
  229. return -1;
  230. }
  231. for (i = 0; i < count; i++)
  232. {
  233. if (decode_open_type(buf, len, &ptr, &bufs[total_count + i], &lengths[total_count + i]) != 0)
  234. return -1;
  235. }
  236. total_count += count;
  237. }
  238. while (stat > 0);
  239. /* We should now be exactly at the end of the packet. If not, this is a fault. */
  240. if (ptr != len)
  241. return -1;
  242. if (seq_no > s->rx_seq_no)
  243. {
  244. /* We received a later packet than we expected, so we need to check if we can fill in the gap from the
  245. secondary packets. */
  246. /* Step through in reverse order, so we go oldest to newest */
  247. for (i = total_count; i > 0; i--)
  248. {
  249. if (seq_no - i >= s->rx_seq_no)
  250. {
  251. /* This one wasn't seen before */
  252. /* Process the secondary packet */
  253. #if defined(UDPTL_DEBUG)
  254. fprintf(stderr, "Secondary %d, len %d\n", seq_no - i, lengths[i - 1]);
  255. #endif
  256. /* Save the new packet. Redundancy mode won't use this, but some systems will switch into
  257. FEC mode after sending some redundant packets, and this may then be important. */
  258. x = (seq_no - i) & UDPTL_BUF_MASK;
  259. if (lengths[i - 1] > 0)
  260. memcpy(s->rx[x].buf, bufs[i - 1], lengths[i - 1]);
  261. s->rx[x].buf_len = lengths[i - 1];
  262. s->rx[x].fec_len[0] = 0;
  263. s->rx[x].fec_span = 0;
  264. s->rx[x].fec_entries = 0;
  265. if (s->rx_packet_handler(s->user_data, bufs[i - 1], lengths[i - 1], seq_no - i) < 0)
  266. fprintf(stderr, "Bad IFP\n");
  267. }
  268. }
  269. }
  270. }
  271. else
  272. {
  273. /* FEC mode for error recovery */
  274. /* Decode the FEC packets */
  275. /* The span is defined as an unconstrained integer, but will never be more
  276. than a small value. */
  277. if (ptr + 2 > len)
  278. return -1;
  279. if (buf[ptr++] != 1)
  280. return -1;
  281. span = buf[ptr++];
  282. x = seq_no & UDPTL_BUF_MASK;
  283. s->rx[x].fec_span = span;
  284. memset(repaired, 0, sizeof(repaired));
  285. repaired[x] = true;
  286. /* The number of entries is defined as a length, but will only ever be a small
  287. value. Treat it as such. */
  288. if (ptr + 1 > len)
  289. return -1;
  290. entries = buf[ptr++];
  291. s->rx[x].fec_entries = entries;
  292. /* Decode the elements */
  293. for (i = 0; i < entries; i++)
  294. {
  295. if ((stat = decode_open_type(buf, len, &ptr, &data, &s->rx[x].fec_len[i])) != 0)
  296. return -1;
  297. if (s->rx[x].fec_len[i] > LOCAL_FAX_MAX_DATAGRAM)
  298. return -1;
  299. /* Save the new FEC data */
  300. if (s->rx[x].fec_len[i])
  301. memcpy(s->rx[x].fec[i], data, s->rx[x].fec_len[i]);
  302. #if 0
  303. fprintf(stderr, "FEC: ");
  304. for (j = 0; j < s->rx[x].fec_len[i]; j++)
  305. fprintf(stderr, "%02X ", data[j]);
  306. fprintf(stderr, "\n");
  307. #endif
  308. }
  309. /* We should now be exactly at the end of the packet. If not, this is a fault. */
  310. if (ptr != len)
  311. return -1;
  312. /* See if we can reconstruct anything which is missing */
  313. /* TODO: this does not comprehensively hunt back and repair everything that is possible */
  314. for (l = x; l != ((x - (16 - span*entries)) & UDPTL_BUF_MASK); l = (l - 1) & UDPTL_BUF_MASK)
  315. {
  316. if (s->rx[l].fec_len[0] <= 0)
  317. continue;
  318. for (m = 0; m < s->rx[l].fec_entries; m++)
  319. {
  320. limit = (l + m) & UDPTL_BUF_MASK;
  321. for (which = -1, k = (limit - s->rx[l].fec_span*s->rx[l].fec_entries) & UDPTL_BUF_MASK;
  322. k != limit;
  323. k = (k + s->rx[l].fec_entries) & UDPTL_BUF_MASK)
  324. {
  325. if (s->rx[k].buf_len <= 0)
  326. which = (which == -1) ? k : -2;
  327. }
  328. if (which >= 0)
  329. {
  330. /* Repairable */
  331. for (j = 0; j < s->rx[l].fec_len[m]; j++)
  332. {
  333. s->rx[which].buf[j] = s->rx[l].fec[m][j];
  334. for (k = (limit - s->rx[l].fec_span*s->rx[l].fec_entries) & UDPTL_BUF_MASK;
  335. k != limit;
  336. k = (k + s->rx[l].fec_entries) & UDPTL_BUF_MASK)
  337. {
  338. s->rx[which].buf[j] ^= (s->rx[k].buf_len > j) ? s->rx[k].buf[j] : 0;
  339. }
  340. }
  341. s->rx[which].buf_len = s->rx[l].fec_len[m];
  342. repaired[which] = true;
  343. }
  344. }
  345. }
  346. /* Now play any new packets forwards in time */
  347. for (l = (x + 1) & UDPTL_BUF_MASK, j = seq_no - UDPTL_BUF_MASK; l != x; l = (l + 1) & UDPTL_BUF_MASK, j++)
  348. {
  349. if (repaired[l])
  350. {
  351. #if defined(UDPTL_DEBUG)
  352. fprintf(stderr, "Fixed packet %d, len %d\n", j, l);
  353. #endif
  354. if (s->rx_packet_handler(s->user_data, s->rx[l].buf, s->rx[l].buf_len, j) < 0)
  355. fprintf(stderr, "Bad IFP\n");
  356. }
  357. }
  358. }
  359. /* If packets are received out of sequence, we may have already processed this packet
  360. from the error recovery information in a packet already received. */
  361. if (seq_no >= s->rx_seq_no)
  362. {
  363. /* Decode the primary packet */
  364. #if defined(UDPTL_DEBUG)
  365. fprintf(stderr, "Primary packet %d, len %d\n", seq_no, msg_len);
  366. #endif
  367. if (s->rx_packet_handler(s->user_data, msg, msg_len, seq_no) < 0)
  368. fprintf(stderr, "Bad IFP\n");
  369. }
  370. s->rx_seq_no = (seq_no + 1) & 0xFFFF;
  371. return 0;
  372. }
  373. /*- End of function --------------------------------------------------------*/
  374. int udptl_build_packet(udptl_state_t *s, uint8_t buf[], const uint8_t msg[], int msg_len)
  375. {
  376. uint8_t fec[LOCAL_FAX_MAX_DATAGRAM];
  377. int i;
  378. int j;
  379. int seq;
  380. int entry;
  381. int entries;
  382. int span;
  383. int m;
  384. int len;
  385. int limit;
  386. int high_tide;
  387. int len_before_entries;
  388. int previous_len;
  389. /* UDPTL cannot cope with zero length messages, and our buffering for redundancy limits their
  390. maximum length. */
  391. if (msg_len < 1 || msg_len > LOCAL_FAX_MAX_DATAGRAM)
  392. return -1;
  393. seq = s->tx_seq_no & 0xFFFF;
  394. /* Map the sequence number to an entry in the circular buffer */
  395. entry = seq & UDPTL_BUF_MASK;
  396. /* We save the message in a circular buffer, for generating FEC or
  397. redundancy sets later on. */
  398. s->tx[entry].buf_len = msg_len;
  399. memcpy(s->tx[entry].buf, msg, msg_len);
  400. /* Build the UDPTL packet */
  401. len = 0;
  402. /* Encode the sequence number */
  403. buf[len++] = (seq >> 8) & 0xFF;
  404. buf[len++] = seq & 0xFF;
  405. /* Encode the primary packet */
  406. if (encode_open_type(buf, &len, msg, msg_len) < 0)
  407. return -1;
  408. /* Encode the appropriate type of error recovery information */
  409. switch (s->error_correction_scheme)
  410. {
  411. case UDPTL_ERROR_CORRECTION_NONE:
  412. /* Encode the error recovery type */
  413. buf[len++] = 0x00;
  414. /* The number of entries will always be zero, so it is pointless allowing
  415. for the fragmented case here. */
  416. if (encode_length(buf, &len, 0) < 0)
  417. return -1;
  418. break;
  419. case UDPTL_ERROR_CORRECTION_REDUNDANCY:
  420. /* Encode the error recovery type */
  421. buf[len++] = 0x00;
  422. if (s->tx_seq_no > s->error_correction_entries)
  423. entries = s->error_correction_entries;
  424. else
  425. entries = s->tx_seq_no;
  426. len_before_entries = len;
  427. /* The number of entries will always be small, so it is pointless allowing
  428. for the fragmented case here. */
  429. if (encode_length(buf, &len, entries) < 0)
  430. return -1;
  431. /* Encode the elements */
  432. for (m = 0; m < entries; m++)
  433. {
  434. previous_len = len;
  435. j = (entry - m - 1) & UDPTL_BUF_MASK;
  436. if (encode_open_type(buf, &len, s->tx[j].buf, s->tx[j].buf_len) < 0)
  437. return -1;
  438. /* If we have exceeded the far end's max datagram size, don't include this last chunk,
  439. and stop trying to add more. */
  440. if (len > s->far_max_datagram_size)
  441. {
  442. len = previous_len;
  443. if (encode_length(buf, &len_before_entries, m) < 0)
  444. return -1;
  445. break;
  446. }
  447. }
  448. break;
  449. case UDPTL_ERROR_CORRECTION_FEC:
  450. span = s->error_correction_span;
  451. entries = s->error_correction_entries;
  452. if (seq < s->error_correction_span*s->error_correction_entries)
  453. {
  454. /* In the initial stages, wind up the FEC smoothly */
  455. entries = seq/s->error_correction_span;
  456. if (seq < s->error_correction_span)
  457. span = 0;
  458. }
  459. /* Encode the error recovery type */
  460. buf[len++] = 0x80;
  461. /* Span is defined as an inconstrained integer, which it dumb. It will only
  462. ever be a small value. Treat it as such. */
  463. buf[len++] = 1;
  464. buf[len++] = span;
  465. /* The number of entries is defined as a length, but will only ever be a small
  466. value. Treat it as such. */
  467. len_before_entries = len;
  468. buf[len++] = entries;
  469. for (m = 0; m < entries; m++)
  470. {
  471. previous_len = len;
  472. /* Make an XOR'ed entry the maximum length */
  473. limit = (entry + m) & UDPTL_BUF_MASK;
  474. high_tide = 0;
  475. for (i = (limit - span*entries) & UDPTL_BUF_MASK; i != limit; i = (i + entries) & UDPTL_BUF_MASK)
  476. {
  477. if (high_tide < s->tx[i].buf_len)
  478. {
  479. for (j = 0; j < high_tide; j++)
  480. fec[j] ^= s->tx[i].buf[j];
  481. for ( ; j < s->tx[i].buf_len; j++)
  482. fec[j] = s->tx[i].buf[j];
  483. high_tide = s->tx[i].buf_len;
  484. }
  485. else
  486. {
  487. for (j = 0; j < s->tx[i].buf_len; j++)
  488. fec[j] ^= s->tx[i].buf[j];
  489. }
  490. }
  491. if (encode_open_type(buf, &len, fec, high_tide) < 0)
  492. return -1;
  493. /* If we have exceeded the far end's max datagram size, don't include this last chunk,
  494. and stop trying to add more. */
  495. if (len > s->far_max_datagram_size)
  496. {
  497. len = previous_len;
  498. buf[len_before_entries] = (uint8_t) m;
  499. break;
  500. }
  501. }
  502. break;
  503. }
  504. if (s->verbose)
  505. fprintf(stderr, "\n");
  506. s->tx_seq_no++;
  507. return len;
  508. }
  509. /*- End of function --------------------------------------------------------*/
  510. int udptl_set_error_correction(udptl_state_t *s,
  511. int ec_scheme,
  512. int span,
  513. int entries)
  514. {
  515. switch (ec_scheme)
  516. {
  517. case UDPTL_ERROR_CORRECTION_FEC:
  518. case UDPTL_ERROR_CORRECTION_REDUNDANCY:
  519. case UDPTL_ERROR_CORRECTION_NONE:
  520. s->error_correction_scheme = ec_scheme;
  521. break;
  522. case -1:
  523. /* Just don't change the scheme */
  524. break;
  525. default:
  526. return -1;
  527. }
  528. if (span >= 0)
  529. s->error_correction_span = span;
  530. if (entries >= 0)
  531. s->error_correction_entries = entries;
  532. return 0;
  533. }
  534. /*- End of function --------------------------------------------------------*/
  535. int udptl_get_error_correction(udptl_state_t *s, int *ec_scheme, int *span, int *entries)
  536. {
  537. if (ec_scheme)
  538. *ec_scheme = s->error_correction_scheme;
  539. if (span)
  540. *span = s->error_correction_span;
  541. if (entries)
  542. *entries = s->error_correction_entries;
  543. return 0;
  544. }
  545. /*- End of function --------------------------------------------------------*/
  546. int udptl_set_local_max_datagram(udptl_state_t *s, int max_datagram)
  547. {
  548. s->local_max_datagram_size = max_datagram;
  549. return 0;
  550. }
  551. /*- End of function --------------------------------------------------------*/
  552. int udptl_get_local_max_datagram(udptl_state_t *s)
  553. {
  554. return s->local_max_datagram_size;
  555. }
  556. /*- End of function --------------------------------------------------------*/
  557. int udptl_set_far_max_datagram(udptl_state_t *s, int max_datagram)
  558. {
  559. s->far_max_datagram_size = max_datagram;
  560. return 0;
  561. }
  562. /*- End of function --------------------------------------------------------*/
  563. int udptl_get_far_max_datagram(udptl_state_t *s)
  564. {
  565. return s->far_max_datagram_size;
  566. }
  567. /*- End of function --------------------------------------------------------*/
  568. udptl_state_t *udptl_init(udptl_state_t *s,
  569. int ec_scheme,
  570. int span,
  571. int entries,
  572. udptl_rx_packet_handler_t rx_packet_handler,
  573. void *user_data)
  574. {
  575. int i;
  576. if (rx_packet_handler == NULL)
  577. return NULL;
  578. if (s == NULL)
  579. {
  580. if ((s = (udptl_state_t *) malloc(sizeof(*s))) == NULL)
  581. return NULL;
  582. }
  583. memset(s, 0, sizeof(*s));
  584. s->error_correction_scheme = ec_scheme;
  585. s->error_correction_span = span;
  586. s->error_correction_entries = entries;
  587. s->far_max_datagram_size = LOCAL_FAX_MAX_DATAGRAM;
  588. s->local_max_datagram_size = LOCAL_FAX_MAX_DATAGRAM;
  589. memset(&s->rx, 0, sizeof(s->rx));
  590. memset(&s->tx, 0, sizeof(s->tx));
  591. for (i = 0; i <= UDPTL_BUF_MASK; i++)
  592. {
  593. s->rx[i].buf_len = -1;
  594. s->tx[i].buf_len = -1;
  595. }
  596. s->rx_packet_handler = rx_packet_handler;
  597. s->user_data = user_data;
  598. return s;
  599. }
  600. /*- End of function --------------------------------------------------------*/
  601. int udptl_release(udptl_state_t *s)
  602. {
  603. return 0;
  604. }
  605. /*- End of function --------------------------------------------------------*/
  606. /*- End of file ------------------------------------------------------------*/