blob: 3bb9afcd39d050d10d6759ca8287ab82d1113a8e [file] [log] [blame]
Philipp0b11db72016-08-01 18:13:40 +02001/*
2 * SpanDSP - a series of DSP components for telephony
3 *
4 * v42bis.c
5 *
6 * Written by Steve Underwood <steveu@coppice.org>
7 *
8 * Copyright (C) 2005, 2011 Steve Underwood
9 *
10 * All rights reserved.
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU Lesser General Public License version 2.1,
14 * as published by the Free Software Foundation.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License for more details.
20 *
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 */
25
26/* THIS IS A WORK IN PROGRESS. IT IS NOT FINISHED.
27 Currently it performs the core compression and decompression functions OK.
28 However, a number of the bells and whistles in V.42bis are incomplete. */
29
30/*! \file */
31
Philipp0b11db72016-08-01 18:13:40 +020032#include <stdio.h>
33#include <stdlib.h>
34#include <inttypes.h>
35#include <string.h>
36#include <errno.h>
37#include <fcntl.h>
38#include <ctype.h>
39#include <assert.h>
40
Neels Hofmeyr396f2e62017-09-04 15:13:25 +020041#include <osmocom/sgsn/v42bis.h>
42#include <osmocom/sgsn/v42bis_private.h>
43#include <osmocom/sgsn/debug.h>
Philippd8b45772016-09-02 13:32:38 +020044#include <osmocom/core/talloc.h>
Philipp0b11db72016-08-01 18:13:40 +020045
Philippd8b45772016-09-02 13:32:38 +020046
47#define span_log(x,y,msg, ...) DEBUGP(DV42BIS,msg, ##__VA_ARGS__)
48#define span_log_init(x,y,z)
49#define span_log_set_protocol(x,y)
50
51
52#define FALSE 0
53#define TRUE 1
Philipp0b11db72016-08-01 18:13:40 +020054
55/* Fixed parameters from the spec. */
56/* Character size (bits) */
57#define V42BIS_N3 8
58/* Number of characters in the alphabet */
59#define V42BIS_N4 256
60/* Index number of first dictionary entry used to store a string */
61#define V42BIS_N5 (V42BIS_N4 + V42BIS_N6)
62/* Number of control codewords */
63#define V42BIS_N6 3
64/* V.42bis/9.2 */
65#define V42BIS_ESC_STEP 51
66
67/* Compreeibility monitoring parameters for assessing automated switches between
68 transparent and compressed mode */
69#define COMPRESSIBILITY_MONITOR (256*V42BIS_N3)
70#define COMPRESSIBILITY_MONITOR_HYSTERESIS 11
71
72/* Control code words in compressed mode */
73enum
74{
75 V42BIS_ETM = 0, /* Enter transparent mode */
76 V42BIS_FLUSH = 1, /* Flush data */
77 V42BIS_STEPUP = 2 /* Step up codeword size */
78};
79
80/* Command codes in transparent mode */
81enum
82{
83 V42BIS_ECM = 0, /* Enter compression mode */
84 V42BIS_EID = 1, /* Escape character in data */
85 V42BIS_RESET = 2 /* Force reinitialisation */
86};
87
88static __inline__ void push_octet(v42bis_comp_state_t *s, int octet)
89{
90 s->output_buf[s->output_octet_count++] = (uint8_t) octet;
91 if (s->output_octet_count >= s->max_output_len)
92 {
93 s->handler(s->user_data, s->output_buf, s->output_octet_count);
94 s->output_octet_count = 0;
95 }
96}
97/*- End of function --------------------------------------------------------*/
98
99static __inline__ void push_octets(v42bis_comp_state_t *s, const uint8_t buf[], int len)
100{
101 int i;
102 int chunk;
103
104 i = 0;
105 while ((s->output_octet_count + len - i) >= s->max_output_len)
106 {
107 chunk = s->max_output_len - s->output_octet_count;
108 memcpy(&s->output_buf[s->output_octet_count], &buf[i], chunk);
109 s->handler(s->user_data, s->output_buf, s->max_output_len);
110 s->output_octet_count = 0;
111 i += chunk;
112 }
113 chunk = len - i;
114 if (chunk > 0)
115 {
116 memcpy(&s->output_buf[s->output_octet_count], &buf[i], chunk);
117 s->output_octet_count += chunk;
118 }
119}
120/*- End of function --------------------------------------------------------*/
121
122static __inline__ void push_compressed_code(v42bis_comp_state_t *s, int code)
123{
124 s->bit_buffer |= code << s->bit_count;
125 s->bit_count += s->v42bis_parm_c2;
126 while (s->bit_count >= 8)
127 {
128 push_octet(s, s->bit_buffer & 0xFF);
129 s->bit_buffer >>= 8;
130 s->bit_count -= 8;
131 }
132}
133/*- End of function --------------------------------------------------------*/
134
135static __inline__ void push_octet_alignment(v42bis_comp_state_t *s)
136{
137 if ((s->bit_count & 7))
138 {
139 s->bit_count += (8 - (s->bit_count & 7));
140 while (s->bit_count >= 8)
141 {
142 push_octet(s, s->bit_buffer & 0xFF);
143 s->bit_buffer >>= 8;
144 s->bit_count -= 8;
145 }
146 }
147}
148/*- End of function --------------------------------------------------------*/
149
150static __inline__ void flush_octets(v42bis_comp_state_t *s)
151{
152 if (s->output_octet_count > 0)
153 {
154 s->handler(s->user_data, s->output_buf, s->output_octet_count);
155 s->output_octet_count = 0;
156 }
157}
158/*- End of function --------------------------------------------------------*/
159
160static void dictionary_init(v42bis_comp_state_t *s)
161{
162 int i;
163
164 memset(s->dict, 0, sizeof(s->dict));
165 for (i = 0; i < V42BIS_N4; i++)
166 s->dict[i + V42BIS_N6].node_octet = i;
167 s->v42bis_parm_c1 = V42BIS_N5;
168 s->v42bis_parm_c2 = V42BIS_N3 + 1;
169 s->v42bis_parm_c3 = V42BIS_N4 << 1;
170 s->last_matched = 0;
171 s->update_at = 0;
172 s->last_added = 0;
173 s->bit_buffer = 0;
174 s->bit_count = 0;
175 s->flushed_length = 0;
176 s->string_length = 0;
177 s->escape_code = 0;
178 s->transparent = TRUE;
179 s->escaped = FALSE;
180 s->compression_performance = COMPRESSIBILITY_MONITOR;
181}
182/*- End of function --------------------------------------------------------*/
183
184static uint16_t match_octet(v42bis_comp_state_t *s, uint16_t at, uint8_t octet)
185{
186 uint16_t e;
187
188 if (at == 0)
189 return octet + V42BIS_N6;
190 e = s->dict[at].child;
191 while (e)
192 {
193 if (s->dict[e].node_octet == octet)
194 return e;
195 e = s->dict[e].next;
196 }
197 return 0;
198}
199/*- End of function --------------------------------------------------------*/
200
201static uint16_t add_octet_to_dictionary(v42bis_comp_state_t *s, uint16_t at, uint8_t octet)
202{
203 uint16_t newx;
204 uint16_t next;
205 uint16_t e;
206
207 newx = s->v42bis_parm_c1;
208 s->dict[newx].node_octet = octet;
209 s->dict[newx].parent = at;
210 s->dict[newx].child = 0;
211 s->dict[newx].next = s->dict[at].child;
212 s->dict[at].child = newx;
213 next = newx;
214 /* 6.5 Recovering a dictionary entry to use next */
215 do
216 {
217 /* 6.5(a) and (b) */
218 if (++next == s->v42bis_parm_n2)
219 next = V42BIS_N5;
220 }
221 while (s->dict[next].child);
222 /* 6.5(c) We need to reuse a leaf node */
223 if (s->dict[next].parent)
224 {
225 /* 6.5(d) Detach the leaf node from its parent, and re-use it */
226 e = s->dict[next].parent;
227 if (s->dict[e].child == next)
228 {
229 s->dict[e].child = s->dict[next].next;
230 }
231 else
232 {
233 e = s->dict[e].child;
234 while (s->dict[e].next != next)
235 e = s->dict[e].next;
236 s->dict[e].next = s->dict[next].next;
237 }
238 }
239 s->v42bis_parm_c1 = next;
240 return newx;
241}
242/*- End of function --------------------------------------------------------*/
243
244static void send_string(v42bis_comp_state_t *s)
245{
246 push_octets(s, s->string, s->string_length);
247 s->string_length = 0;
248 s->flushed_length = 0;
249}
250/*- End of function --------------------------------------------------------*/
251
252static void expand_codeword_to_string(v42bis_comp_state_t *s, uint16_t code)
253{
254 int i;
255 uint16_t p;
256
257 /* Work out the length */
258 for (i = 0, p = code; p; i++)
259 p = s->dict[p].parent;
260 s->string_length += i;
261 /* Now expand the known length of string */
262 i = s->string_length - 1;
263 for (p = code; p; )
264 {
265 s->string[i--] = s->dict[p].node_octet;
266 p = s->dict[p].parent;
267 }
268}
269/*- End of function --------------------------------------------------------*/
270
271static void send_encoded_data(v42bis_comp_state_t *s, uint16_t code)
272{
273 int i;
274
275 /* Update compressibility metric */
276 /* Integrate at the compressed bit rate, and leak at the pre-compression bit rate */
277 s->compression_performance += (s->v42bis_parm_c2 - s->compression_performance*s->string_length*V42BIS_N3/COMPRESSIBILITY_MONITOR);
278 if (s->transparent)
279 {
280 for (i = 0; i < s->string_length; i++)
281 {
282 push_octet(s, s->string[i]);
283 if (s->string[i] == s->escape_code)
284 {
285 push_octet(s, V42BIS_EID);
286 s->escape_code += V42BIS_ESC_STEP;
287 }
288 }
289 }
290 else
291 {
292 /* Allow for any escape octets in the string */
293 for (i = 0; i < s->string_length; i++)
294 {
295 if (s->string[i] == s->escape_code)
296 s->escape_code += V42BIS_ESC_STEP;
297 }
298 /* 7.4 Encoding - we now have the longest matchable string, and will need to output the code for it. */
299 while (code >= s->v42bis_parm_c3)
300 {
301 /* We need to increase the codeword size */
302 /* 7.4(a) */
303 push_compressed_code(s, V42BIS_STEPUP);
304 /* 7.4(b) */
305 s->v42bis_parm_c2++;
306 /* 7.4(c) */
307 s->v42bis_parm_c3 <<= 1;
308 /* 7.4(d) this might need to be repeated, so we loop */
309 }
310 /* 7.5 Transfer - output the last state of the string */
311 push_compressed_code(s, code);
312 }
313 s->string_length = 0;
314 s->flushed_length = 0;
315}
316/*- End of function --------------------------------------------------------*/
317
318static void go_compressed(v42bis_state_t *ss)
319{
320 v42bis_comp_state_t *s;
321
322 s = &ss->compress;
323 if (!s->transparent)
324 return;
325 span_log(&ss->logging, SPAN_LOG_FLOW, "Changing to compressed mode\n");
326 /* Switch out of transparent now, between codes. We need to send the octet which did not
327 match, just before switching. */
328 if (s->last_matched)
329 {
330 s->update_at = s->last_matched;
331 send_encoded_data(s, s->last_matched);
332 s->last_matched = 0;
333 }
334 push_octet(s, s->escape_code);
335 push_octet(s, V42BIS_ECM);
336 s->bit_buffer = 0;
337 s->transparent = FALSE;
338}
339/*- End of function --------------------------------------------------------*/
340
341static void go_transparent(v42bis_state_t *ss)
342{
343 v42bis_comp_state_t *s;
344
345 s = &ss->compress;
346 if (s->transparent)
347 return;
348 span_log(&ss->logging, SPAN_LOG_FLOW, "Changing to transparent mode\n");
349 /* Switch into transparent now, between codes, and the unmatched octet should
350 go out in transparent mode, just below */
351 if (s->last_matched)
352 {
353 s->update_at = s->last_matched;
354 send_encoded_data(s, s->last_matched);
355 s->last_matched = 0;
356 }
357 s->last_added = 0;
358 push_compressed_code(s, V42BIS_ETM);
359 push_octet_alignment(s);
360 s->transparent = TRUE;
361}
362/*- End of function --------------------------------------------------------*/
363
364static void monitor_for_mode_change(v42bis_state_t *ss)
365{
366 v42bis_comp_state_t *s;
367
368 s = &ss->compress;
369 switch (s->compression_mode)
370 {
371 case V42BIS_COMPRESSION_MODE_DYNAMIC:
372 /* 7.8 Data compressibility test */
373 if (s->transparent)
374 {
375 if (s->compression_performance < COMPRESSIBILITY_MONITOR - COMPRESSIBILITY_MONITOR_HYSTERESIS)
376 {
377 /* 7.8.1 Transition to compressed mode */
378 go_compressed(ss);
379 }
380 }
381 else
382 {
383 if (s->compression_performance > COMPRESSIBILITY_MONITOR)
384 {
385 /* 7.8.2 Transition to transparent mode */
386 go_transparent(ss);
387 }
388 }
389 /* 7.8.3 Reset function - TODO */
390 break;
391 case V42BIS_COMPRESSION_MODE_ALWAYS:
392 if (s->transparent)
393 go_compressed(ss);
394 break;
395 case V42BIS_COMPRESSION_MODE_NEVER:
396 if (!s->transparent)
397 go_transparent(ss);
398 break;
399 }
400}
401/*- End of function --------------------------------------------------------*/
402
403static int v42bis_comp_init(v42bis_comp_state_t *s,
404 int p1,
405 int p2,
406 put_msg_func_t handler,
407 void *user_data,
408 int max_output_len)
409{
410 memset(s, 0, sizeof(*s));
411 s->v42bis_parm_n2 = p1;
412 s->v42bis_parm_n7 = p2;
413 s->handler = handler;
414 s->user_data = user_data;
415 s->max_output_len = (max_output_len < V42BIS_MAX_OUTPUT_LENGTH) ? max_output_len : V42BIS_MAX_OUTPUT_LENGTH;
416 s->output_octet_count = 0;
417 dictionary_init(s);
418 return 0;
419}
420/*- End of function --------------------------------------------------------*/
421
422static int comp_exit(v42bis_comp_state_t *s)
423{
424 s->v42bis_parm_n2 = 0;
425 return 0;
426}
427/*- End of function --------------------------------------------------------*/
428
429SPAN_DECLARE(int) v42bis_compress(v42bis_state_t *ss, const uint8_t buf[], int len)
430{
431 v42bis_comp_state_t *s;
432 int i;
433 uint16_t code;
434
435 s = &ss->compress;
436 if (!s->v42bis_parm_p0)
437 {
438 /* Compression is off - just push the incoming data out */
439 push_octets(s, buf, len);
440 return 0;
441 }
442 for (i = 0; i < len; )
443 {
444 /* 6.4 Add the string to the dictionary */
445 if (s->update_at)
446 {
447 if (match_octet(s, s->update_at, buf[i]) == 0)
448 s->last_added = add_octet_to_dictionary(s, s->update_at, buf[i]);
449 s->update_at = 0;
450 }
451 /* Match string */
452 while (i < len)
453 {
454 code = match_octet(s, s->last_matched, buf[i]);
455 if (code == 0)
456 {
457 s->update_at = s->last_matched;
458 send_encoded_data(s, s->last_matched);
459 s->last_matched = 0;
460 break;
461 }
462 if (code == s->last_added)
463 {
464 s->last_added = 0;
465 send_encoded_data(s, s->last_matched);
466 s->last_matched = 0;
467 break;
468 }
469 s->last_matched = code;
470 /* 6.3(b) If the string matches a dictionary entry, and the entry is not that entry
471 created by the last invocation of the string matching procedure, then the
472 next character shall be read and appended to the string and this step
473 repeated. */
474 s->string[s->string_length++] = buf[i++];
475 /* 6.4(a) The string must not exceed N7 in length */
476 if (s->string_length + s->flushed_length == s->v42bis_parm_n7)
477 {
478 send_encoded_data(s, s->last_matched);
479 s->last_matched = 0;
480 break;
481 }
482 }
483 monitor_for_mode_change(ss);
484 }
485 return 0;
486}
487/*- End of function --------------------------------------------------------*/
488
489SPAN_DECLARE(int) v42bis_compress_flush(v42bis_state_t *ss)
490{
491 v42bis_comp_state_t *s;
492 int len;
493
494 s = &ss->compress;
495 if (s->update_at)
496 return 0;
497 if (s->last_matched)
498 {
499 len = s->string_length;
500 send_encoded_data(s, s->last_matched);
501 s->flushed_length += len;
502 }
503 if (!s->transparent)
504 {
505 s->update_at = s->last_matched;
506 s->last_matched = 0;
507 s->flushed_length = 0;
508 push_compressed_code(s, V42BIS_FLUSH);
509 push_octet_alignment(s);
510 }
511 flush_octets(s);
512 return 0;
513}
514/*- End of function --------------------------------------------------------*/
515
516SPAN_DECLARE(int) v42bis_decompress(v42bis_state_t *ss, const uint8_t buf[], int len)
517{
518 v42bis_comp_state_t *s;
519 int i;
520 int j;
521 int yyy;
522 uint16_t code;
523 uint16_t p;
524 uint8_t ch;
525 uint8_t in;
526
527 s = &ss->decompress;
528 if (!s->v42bis_parm_p0)
529 {
530 /* Compression is off - just push the incoming data out */
531 push_octets(s, buf, len);
532 return 0;
533 }
534 for (i = 0; i < len; )
535 {
536 if (s->transparent)
537 {
538 in = buf[i];
539 if (s->escaped)
540 {
541 /* Command */
542 s->escaped = FALSE;
543 switch (in)
544 {
545 case V42BIS_ECM:
546 /* Enter compressed mode */
547 span_log(&ss->logging, SPAN_LOG_FLOW, "Hit V42BIS_ECM\n");
548 send_string(s);
549 s->transparent = FALSE;
550 s->update_at = s->last_matched;
551 s->last_matched = 0;
552 i++;
553 continue;
554 case V42BIS_EID:
555 /* Escape symbol */
556 span_log(&ss->logging, SPAN_LOG_FLOW, "Hit V42BIS_EID\n");
557 in = s->escape_code;
558 s->escape_code += V42BIS_ESC_STEP;
559 break;
560 case V42BIS_RESET:
561 /* Reset dictionary */
562 span_log(&ss->logging, SPAN_LOG_FLOW, "Hit V42BIS_RESET\n");
563 /* TODO: */
564 send_string(s);
565 dictionary_init(s);
566 i++;
567 continue;
568 default:
569 span_log(&ss->logging, SPAN_LOG_FLOW, "Hit V42BIS_???? - %" PRIu32 "\n", in);
570 return -1;
571 }
572 }
573 else if (in == s->escape_code)
574 {
575 s->escaped = TRUE;
576 i++;
577 continue;
578 }
579
580 yyy = TRUE;
581 for (j = 0; j < 2 && yyy; j++)
582 {
583 if (s->update_at)
584 {
585 if (match_octet(s, s->update_at, in) == 0)
586 s->last_added = add_octet_to_dictionary(s, s->update_at, in);
587 s->update_at = 0;
588 }
589
590 code = match_octet(s, s->last_matched, in);
591 if (code == 0)
592 {
593 s->update_at = s->last_matched;
594 send_string(s);
595 s->last_matched = 0;
596 }
597 else if (code == s->last_added)
598 {
599 s->last_added = 0;
600 send_string(s);
601 s->last_matched = 0;
602 }
603 else
604 {
605 s->last_matched = code;
606 s->string[s->string_length++] = in;
607 if (s->string_length + s->flushed_length == s->v42bis_parm_n7)
608 {
609 send_string(s);
610 s->last_matched = 0;
611 }
612 i++;
613 yyy = FALSE;
614 }
615 }
616 }
617 else
618 {
619 /* Get code from input */
620 while (s->bit_count < s->v42bis_parm_c2 && i < len)
621 {
622 s->bit_buffer |= buf[i++] << s->bit_count;
623 s->bit_count += 8;
624 }
625 if (s->bit_count < s->v42bis_parm_c2)
626 continue;
627 code = s->bit_buffer & ((1 << s->v42bis_parm_c2) - 1);
628 s->bit_buffer >>= s->v42bis_parm_c2;
629 s->bit_count -= s->v42bis_parm_c2;
630
631 if (code < V42BIS_N6)
632 {
633 /* We have a control code. */
634 switch (code)
635 {
636 case V42BIS_ETM:
637 /* Enter transparent mode */
638 span_log(&ss->logging, SPAN_LOG_FLOW, "Hit V42BIS_ETM\n");
639 s->bit_count = 0;
640 s->transparent = TRUE;
641 s->last_matched = 0;
642 s->last_added = 0;
643 break;
644 case V42BIS_FLUSH:
645 /* Flush signal */
646 span_log(&ss->logging, SPAN_LOG_FLOW, "Hit V42BIS_FLUSH\n");
647 s->bit_count = 0;
648 break;
649 case V42BIS_STEPUP:
650 /* Increase code word size */
651 span_log(&ss->logging, SPAN_LOG_FLOW, "Hit V42BIS_STEPUP\n");
652 s->v42bis_parm_c2++;
653 s->v42bis_parm_c3 <<= 1;
654 if (s->v42bis_parm_c2 > (s->v42bis_parm_n2 >> 3))
655 return -1;
656 break;
657 }
658 continue;
659 }
660 /* Regular codeword */
661 if (code == s->v42bis_parm_c1)
662 return -1;
663 expand_codeword_to_string(s, code);
664 if (s->update_at)
665 {
666 ch = s->string[0];
667 if ((p = match_octet(s, s->update_at, ch)) == 0)
668 {
669 s->last_added = add_octet_to_dictionary(s, s->update_at, ch);
670 if (code == s->v42bis_parm_c1)
671 return -1;
672 }
673 else if (p == s->last_added)
674 {
675 s->last_added = 0;
676 }
677 }
678 s->update_at = ((s->string_length + s->flushed_length) == s->v42bis_parm_n7) ? 0 : code;
679 /* Allow for any escapes which may be in this string */
680 for (j = 0; j < s->string_length; j++)
681 {
682 if (s->string[j] == s->escape_code)
683 s->escape_code += V42BIS_ESC_STEP;
684 }
685 send_string(s);
686 }
687 }
688 return 0;
689}
690/*- End of function --------------------------------------------------------*/
691
692SPAN_DECLARE(int) v42bis_decompress_flush(v42bis_state_t *ss)
693{
694 v42bis_comp_state_t *s;
695 int len;
696
697 s = &ss->decompress;
698 len = s->string_length;
699 send_string(s);
700 s->flushed_length += len;
701 flush_octets(s);
702 return 0;
703}
704/*- End of function --------------------------------------------------------*/
705
706SPAN_DECLARE(void) v42bis_compression_control(v42bis_state_t *s, int mode)
707{
708 s->compress.compression_mode = mode;
709}
710/*- End of function --------------------------------------------------------*/
711
Philippd8b45772016-09-02 13:32:38 +0200712SPAN_DECLARE(v42bis_state_t *) v42bis_init(const void *ctx,
713 v42bis_state_t *s,
Philipp0b11db72016-08-01 18:13:40 +0200714 int negotiated_p0,
715 int negotiated_p1,
716 int negotiated_p2,
717 put_msg_func_t encode_handler,
718 void *encode_user_data,
719 int max_encode_len,
720 put_msg_func_t decode_handler,
721 void *decode_user_data,
722 int max_decode_len)
723{
724 int ret;
725
726 if (negotiated_p1 < V42BIS_MIN_DICTIONARY_SIZE || negotiated_p1 > 65535)
727 return NULL;
728 if (negotiated_p2 < V42BIS_MIN_STRING_SIZE || negotiated_p2 > V42BIS_MAX_STRING_SIZE)
729 return NULL;
730 if (s == NULL)
731 {
Philippd8b45772016-09-02 13:32:38 +0200732 if ((s = (v42bis_state_t *) talloc_zero_size(ctx,sizeof(*s))) == NULL)
Philipp0b11db72016-08-01 18:13:40 +0200733 return NULL;
734 }
735 memset(s, 0, sizeof(*s));
736 span_log_init(&s->logging, SPAN_LOG_NONE, NULL);
737 span_log_set_protocol(&s->logging, "V.42bis");
738
739 if ((ret = v42bis_comp_init(&s->compress, negotiated_p1, negotiated_p2, encode_handler, encode_user_data, max_encode_len)))
740 return NULL;
741 if ((ret = v42bis_comp_init(&s->decompress, negotiated_p1, negotiated_p2, decode_handler, decode_user_data, max_decode_len)))
742 {
743 comp_exit(&s->compress);
744 return NULL;
745 }
746 s->compress.v42bis_parm_p0 = negotiated_p0 & 2;
747 s->decompress.v42bis_parm_p0 = negotiated_p0 & 1;
748
749 return s;
750}
751/*- End of function --------------------------------------------------------*/
752
753SPAN_DECLARE(int) v42bis_release(v42bis_state_t *s)
754{
755 return 0;
756}
757/*- End of function --------------------------------------------------------*/
758
759SPAN_DECLARE(int) v42bis_free(v42bis_state_t *s)
760{
761 comp_exit(&s->compress);
762 comp_exit(&s->decompress);
Philippd8b45772016-09-02 13:32:38 +0200763 talloc_free(s);
Philipp0b11db72016-08-01 18:13:40 +0200764 return 0;
765}
766/*- End of function --------------------------------------------------------*/
767/*- End of file ------------------------------------------------------------*/