xref: /freebsd/usr.sbin/ppp/deflate.c (revision 817420dc8eac7df799c78f5309b75092b7f7cd40)
1 /*-
2  * Copyright (c) 1997 Brian Somers <brian@Awfulhak.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  * $FreeBSD$
27  */
28 
29 #include <sys/types.h>
30 
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <termios.h>
34 #include <zlib.h>
35 
36 #include "defs.h"
37 #include "mbuf.h"
38 #include "log.h"
39 #include "timer.h"
40 #include "fsm.h"
41 #include "lqr.h"
42 #include "hdlc.h"
43 #include "lcp.h"
44 #include "ccp.h"
45 #include "deflate.h"
46 
47 /* Our state */
48 struct deflate_state {
49     u_short seqno;
50     int uncomp_rec;
51     int winsize;
52     z_stream cx;
53 };
54 
55 static char garbage[10];
56 static u_char EMPTY_BLOCK[4] = { 0x00, 0x00, 0xff, 0xff };
57 
58 #define DEFLATE_CHUNK_LEN (1536 - sizeof(struct mbuf))
59 
60 static void
61 DeflateResetOutput(void *v)
62 {
63   struct deflate_state *state = (struct deflate_state *)v;
64 
65   state->seqno = 0;
66   state->uncomp_rec = 0;
67   deflateReset(&state->cx);
68   log_Printf(LogCCP, "Deflate: Output channel reset\n");
69 }
70 
71 static struct mbuf *
72 DeflateOutput(void *v, struct ccp *ccp, struct link *l, int pri, u_short *proto,
73               struct mbuf *mp)
74 {
75   struct deflate_state *state = (struct deflate_state *)v;
76   u_char *wp, *rp;
77   int olen, ilen, len, res, flush;
78   struct mbuf *mo_head, *mo, *mi_head, *mi;
79 
80   ilen = m_length(mp);
81   log_Printf(LogDEBUG, "DeflateOutput: Proto %02x (%d bytes)\n", *proto, ilen);
82   log_DumpBp(LogDEBUG, "DeflateOutput: Compress packet:", mp);
83 
84   /* Stuff the protocol in front of the input */
85   mi_head = mi = m_get(2, MB_CCPOUT);
86   mi->m_next = mp;
87   rp = MBUF_CTOP(mi);
88   if (*proto < 0x100) {			/* Compress the protocol */
89     rp[0] = *proto & 0377;
90     mi->m_len = 1;
91   } else {				/* Don't compress the protocol */
92     rp[0] = *proto >> 8;
93     rp[1] = *proto & 0377;
94     mi->m_len = 2;
95   }
96 
97   /* Allocate the initial output mbuf */
98   mo_head = mo = m_get(DEFLATE_CHUNK_LEN, MB_CCPOUT);
99   mo->m_len = 2;
100   wp = MBUF_CTOP(mo);
101   *wp++ = state->seqno >> 8;
102   *wp++ = state->seqno & 0377;
103   log_Printf(LogDEBUG, "DeflateOutput: Seq %d\n", state->seqno);
104   state->seqno++;
105 
106   /* Set up the deflation context */
107   state->cx.next_out = wp;
108   state->cx.avail_out = DEFLATE_CHUNK_LEN - 2;
109   state->cx.next_in = MBUF_CTOP(mi);
110   state->cx.avail_in = mi->m_len;
111   flush = Z_NO_FLUSH;
112 
113   olen = 0;
114   while (1) {
115     if ((res = deflate(&state->cx, flush)) != Z_OK) {
116       if (res == Z_STREAM_END)
117         break;			/* Done */
118       log_Printf(LogWARN, "DeflateOutput: deflate returned %d (%s)\n",
119                 res, state->cx.msg ? state->cx.msg : "");
120       m_freem(mo_head);
121       m_free(mi_head);
122       state->seqno--;
123       return mp;		/* Our dictionary's probably dead now :-( */
124     }
125 
126     if (flush == Z_SYNC_FLUSH && state->cx.avail_out != 0)
127       break;
128 
129     if (state->cx.avail_in == 0 && mi->m_next != NULL) {
130       mi = mi->m_next;
131       state->cx.next_in = MBUF_CTOP(mi);
132       state->cx.avail_in = mi->m_len;
133       if (mi->m_next == NULL)
134         flush = Z_SYNC_FLUSH;
135     }
136 
137     if (state->cx.avail_out == 0) {
138       mo->m_next = m_get(DEFLATE_CHUNK_LEN, MB_CCPOUT);
139       olen += (mo->m_len = DEFLATE_CHUNK_LEN);
140       mo = mo->m_next;
141       mo->m_len = 0;
142       state->cx.next_out = MBUF_CTOP(mo);
143       state->cx.avail_out = DEFLATE_CHUNK_LEN;
144     }
145   }
146 
147   olen += (mo->m_len = DEFLATE_CHUNK_LEN - state->cx.avail_out);
148   olen -= 4;		/* exclude the trailing EMPTY_BLOCK */
149 
150   /*
151    * If the output packet (including seqno and excluding the EMPTY_BLOCK)
152    * got bigger, send the original.
153    */
154   if (olen >= ilen) {
155     m_freem(mo_head);
156     m_free(mi_head);
157     log_Printf(LogDEBUG, "DeflateOutput: %d => %d: Uncompressible (0x%04x)\n",
158               ilen, olen, *proto);
159     ccp->uncompout += ilen;
160     ccp->compout += ilen;	/* We measure this stuff too */
161     return mp;
162   }
163 
164   m_freem(mi_head);
165 
166   /*
167    * Lose the last four bytes of our output.
168    * XXX: We should probably assert that these are the same as the
169    *      contents of EMPTY_BLOCK.
170    */
171   mo = mo_head;
172   for (len = mo->m_len; len < olen; mo = mo->m_next, len += mo->m_len)
173     ;
174   mo->m_len -= len - olen;
175   if (mo->m_next != NULL) {
176     m_freem(mo->m_next);
177     mo->m_next = NULL;
178   }
179 
180   ccp->uncompout += ilen;
181   ccp->compout += olen;
182 
183   log_Printf(LogDEBUG, "DeflateOutput: %d => %d bytes, proto 0x%04x\n",
184             ilen, olen, *proto);
185 
186   *proto = ccp_Proto(ccp);
187   return mo_head;
188 }
189 
190 static void
191 DeflateResetInput(void *v)
192 {
193   struct deflate_state *state = (struct deflate_state *)v;
194 
195   state->seqno = 0;
196   state->uncomp_rec = 0;
197   inflateReset(&state->cx);
198   log_Printf(LogCCP, "Deflate: Input channel reset\n");
199 }
200 
201 static struct mbuf *
202 DeflateInput(void *v, struct ccp *ccp, u_short *proto, struct mbuf *mi)
203 {
204   struct deflate_state *state = (struct deflate_state *)v;
205   struct mbuf *mo, *mo_head, *mi_head;
206   u_char *wp;
207   int ilen, olen;
208   int seq, flush, res, first;
209   u_char hdr[2];
210 
211   log_DumpBp(LogDEBUG, "DeflateInput: Decompress packet:", mi);
212   mi_head = mi = mbuf_Read(mi, hdr, 2);
213   ilen = 2;
214 
215   /* Check the sequence number. */
216   seq = (hdr[0] << 8) + hdr[1];
217   log_Printf(LogDEBUG, "DeflateInput: Seq %d\n", seq);
218   if (seq != state->seqno) {
219     if (seq <= state->uncomp_rec)
220       /*
221        * So the peer's started at zero again - fine !  If we're wrong,
222        * inflate() will fail.  This is better than getting into a loop
223        * trying to get a ResetReq to a busy sender.
224        */
225       state->seqno = seq;
226     else {
227       log_Printf(LogCCP, "DeflateInput: Seq error: Got %d, expected %d\n",
228                 seq, state->seqno);
229       m_freem(mi_head);
230       ccp_SendResetReq(&ccp->fsm);
231       return NULL;
232     }
233   }
234   state->seqno++;
235   state->uncomp_rec = 0;
236 
237   /* Allocate an output mbuf */
238   mo_head = mo = m_get(DEFLATE_CHUNK_LEN, MB_CCPIN);
239 
240   /* Our proto starts with 0 if it's compressed */
241   wp = MBUF_CTOP(mo);
242   wp[0] = '\0';
243 
244   /*
245    * We set avail_out to 1 initially so we can look at the first
246    * byte of the output and decide whether we have a compressed
247    * proto field.
248    */
249   state->cx.next_in = MBUF_CTOP(mi);
250   state->cx.avail_in = mi->m_len;
251   state->cx.next_out = wp + 1;
252   state->cx.avail_out = 1;
253   ilen += mi->m_len;
254 
255   flush = mi->m_next ? Z_NO_FLUSH : Z_SYNC_FLUSH;
256   first = 1;
257   olen = 0;
258 
259   while (1) {
260     if ((res = inflate(&state->cx, flush)) != Z_OK) {
261       if (res == Z_STREAM_END)
262         break;			/* Done */
263       log_Printf(LogCCP, "DeflateInput: inflate returned %d (%s)\n",
264                 res, state->cx.msg ? state->cx.msg : "");
265       m_freem(mo_head);
266       m_freem(mi);
267       ccp_SendResetReq(&ccp->fsm);
268       return NULL;
269     }
270 
271     if (flush == Z_SYNC_FLUSH && state->cx.avail_out != 0)
272       break;
273 
274     if (state->cx.avail_in == 0 && mi && (mi = m_free(mi)) != NULL) {
275       /* underflow */
276       state->cx.next_in = MBUF_CTOP(mi);
277       ilen += (state->cx.avail_in = mi->m_len);
278       if (mi->m_next == NULL)
279         flush = Z_SYNC_FLUSH;
280     }
281 
282     if (state->cx.avail_out == 0) {
283       /* overflow */
284       if (first) {
285         if (!(wp[1] & 1)) {
286           /* 2 byte proto, shuffle it back in output */
287           wp[0] = wp[1];
288           state->cx.next_out--;
289           state->cx.avail_out = DEFLATE_CHUNK_LEN-1;
290         } else
291           state->cx.avail_out = DEFLATE_CHUNK_LEN-2;
292         first = 0;
293       } else {
294         olen += (mo->m_len = DEFLATE_CHUNK_LEN);
295         mo->m_next = m_get(DEFLATE_CHUNK_LEN, MB_CCPIN);
296         mo = mo->m_next;
297         state->cx.next_out = MBUF_CTOP(mo);
298         state->cx.avail_out = DEFLATE_CHUNK_LEN;
299       }
300     }
301   }
302 
303   if (mi != NULL)
304     m_freem(mi);
305 
306   if (first) {
307     log_Printf(LogCCP, "DeflateInput: Length error\n");
308     m_freem(mo_head);
309     ccp_SendResetReq(&ccp->fsm);
310     return NULL;
311   }
312 
313   olen += (mo->m_len = DEFLATE_CHUNK_LEN - state->cx.avail_out);
314 
315   *proto = ((u_short)wp[0] << 8) | wp[1];
316   mo_head->m_offset += 2;
317   mo_head->m_len -= 2;
318   olen -= 2;
319 
320   ccp->compin += ilen;
321   ccp->uncompin += olen;
322 
323   log_Printf(LogDEBUG, "DeflateInput: %d => %d bytes, proto 0x%04x\n",
324             ilen, olen, *proto);
325 
326   /*
327    * Simulate an EMPTY_BLOCK so that our dictionary stays in sync.
328    * The peer will have silently removed this!
329    */
330   state->cx.next_out = garbage;
331   state->cx.avail_out = sizeof garbage;
332   state->cx.next_in = EMPTY_BLOCK;
333   state->cx.avail_in = sizeof EMPTY_BLOCK;
334   inflate(&state->cx, Z_SYNC_FLUSH);
335 
336   return mo_head;
337 }
338 
339 static void
340 DeflateDictSetup(void *v, struct ccp *ccp, u_short proto, struct mbuf *mi)
341 {
342   struct deflate_state *state = (struct deflate_state *)v;
343   int res, flush, expect_error;
344   u_char *rp;
345   struct mbuf *mi_head;
346   short len;
347 
348   log_Printf(LogDEBUG, "DeflateDictSetup: Got seq %d\n", state->seqno);
349 
350   /*
351    * Stuff an ``uncompressed data'' block header followed by the
352    * protocol in front of the input
353    */
354   mi_head = m_get(7, MB_CCPOUT);
355   mi_head->m_next = mi;
356   len = m_length(mi);
357   mi = mi_head;
358   rp = MBUF_CTOP(mi);
359   if (proto < 0x100) {			/* Compress the protocol */
360     rp[5] = proto & 0377;
361     mi->m_len = 6;
362     len++;
363   } else {				/* Don't compress the protocol */
364     rp[5] = proto >> 8;
365     rp[6] = proto & 0377;
366     mi->m_len = 7;
367     len += 2;
368   }
369   rp[0] = 0x80;				/* BITS: 100xxxxx */
370   rp[1] = len & 0377;			/* The length */
371   rp[2] = len >> 8;
372   rp[3] = (~len) & 0377;		/* One's compliment of the length */
373   rp[4] = (~len) >> 8;
374 
375   state->cx.next_in = rp;
376   state->cx.avail_in = mi->m_len;
377   state->cx.next_out = garbage;
378   state->cx.avail_out = sizeof garbage;
379   flush = Z_NO_FLUSH;
380   expect_error = 0;
381 
382   while (1) {
383     if ((res = inflate(&state->cx, flush)) != Z_OK) {
384       if (res == Z_STREAM_END)
385         break;			/* Done */
386       if (expect_error && res == Z_BUF_ERROR)
387         break;
388       log_Printf(LogCCP, "DeflateDictSetup: inflate returned %d (%s)\n",
389                 res, state->cx.msg ? state->cx.msg : "");
390       log_Printf(LogCCP, "DeflateDictSetup: avail_in %d, avail_out %d\n",
391                 state->cx.avail_in, state->cx.avail_out);
392       ccp_SendResetReq(&ccp->fsm);
393       m_free(mi_head);		/* lose our allocated ``head'' buf */
394       return;
395     }
396 
397     if (flush == Z_SYNC_FLUSH && state->cx.avail_out != 0)
398       break;
399 
400     if (state->cx.avail_in == 0 && mi && (mi = mi->m_next) != NULL) {
401       /* underflow */
402       state->cx.next_in = MBUF_CTOP(mi);
403       state->cx.avail_in = mi->m_len;
404       if (mi->m_next == NULL)
405         flush = Z_SYNC_FLUSH;
406     }
407 
408     if (state->cx.avail_out == 0) {
409       if (state->cx.avail_in == 0)
410         /*
411          * This seems to be a bug in libz !  If inflate() finished
412          * with 0 avail_in and 0 avail_out *and* this is the end of
413          * our input *and* inflate() *has* actually written all the
414          * output it's going to, it *doesn't* return Z_STREAM_END !
415          * When we subsequently call it with no more input, it gives
416          * us Z_BUF_ERROR :-(  It seems pretty safe to ignore this
417          * error (the dictionary seems to stay in sync).  In the worst
418          * case, we'll drop the next compressed packet and do a
419          * CcpReset() then.
420          */
421         expect_error = 1;
422       /* overflow */
423       state->cx.next_out = garbage;
424       state->cx.avail_out = sizeof garbage;
425     }
426   }
427 
428   ccp->compin += len;
429   ccp->uncompin += len;
430 
431   state->seqno++;
432   state->uncomp_rec++;
433   m_free(mi_head);		/* lose our allocated ``head'' buf */
434 }
435 
436 static const char *
437 DeflateDispOpts(struct lcp_opt *o)
438 {
439   static char disp[7];		/* Must be used immediately */
440 
441   sprintf(disp, "win %d", (o->data[0]>>4) + 8);
442   return disp;
443 }
444 
445 static void
446 DeflateInitOptsOutput(struct lcp_opt *o, const struct ccp_config *cfg)
447 {
448   o->len = 4;
449   o->data[0] = ((cfg->deflate.out.winsize - 8) << 4) + 8;
450   o->data[1] = '\0';
451 }
452 
453 static int
454 DeflateSetOptsOutput(struct lcp_opt *o)
455 {
456   if (o->len != 4 || (o->data[0] & 15) != 8 || o->data[1] != '\0')
457     return MODE_REJ;
458 
459   if ((o->data[0] >> 4) + 8 > 15) {
460     o->data[0] = ((15 - 8) << 4) + 8;
461     return MODE_NAK;
462   }
463 
464   return MODE_ACK;
465 }
466 
467 static int
468 DeflateSetOptsInput(struct lcp_opt *o, const struct ccp_config *cfg)
469 {
470   int want;
471 
472   if (o->len != 4 || (o->data[0] & 15) != 8 || o->data[1] != '\0')
473     return MODE_REJ;
474 
475   want = (o->data[0] >> 4) + 8;
476   if (cfg->deflate.in.winsize == 0) {
477     if (want < 8 || want > 15) {
478       o->data[0] = ((15 - 8) << 4) + 8;
479     }
480   } else if (want != cfg->deflate.in.winsize) {
481     o->data[0] = ((cfg->deflate.in.winsize - 8) << 4) + 8;
482     return MODE_NAK;
483   }
484 
485   return MODE_ACK;
486 }
487 
488 static void *
489 DeflateInitInput(struct lcp_opt *o)
490 {
491   struct deflate_state *state;
492 
493   state = (struct deflate_state *)malloc(sizeof(struct deflate_state));
494   if (state != NULL) {
495     state->winsize = (o->data[0] >> 4) + 8;
496     state->cx.zalloc = NULL;
497     state->cx.opaque = NULL;
498     state->cx.zfree = NULL;
499     state->cx.next_out = NULL;
500     if (inflateInit2(&state->cx, -state->winsize) == Z_OK)
501       DeflateResetInput(state);
502     else {
503       free(state);
504       state = NULL;
505     }
506   }
507 
508   return state;
509 }
510 
511 static void *
512 DeflateInitOutput(struct lcp_opt *o)
513 {
514   struct deflate_state *state;
515 
516   state = (struct deflate_state *)malloc(sizeof(struct deflate_state));
517   if (state != NULL) {
518     state->winsize = (o->data[0] >> 4) + 8;
519     state->cx.zalloc = NULL;
520     state->cx.opaque = NULL;
521     state->cx.zfree = NULL;
522     state->cx.next_in = NULL;
523     if (deflateInit2(&state->cx, Z_DEFAULT_COMPRESSION, 8,
524                      -state->winsize, 8, Z_DEFAULT_STRATEGY) == Z_OK)
525       DeflateResetOutput(state);
526     else {
527       free(state);
528       state = NULL;
529     }
530   }
531 
532   return state;
533 }
534 
535 static void
536 DeflateTermInput(void *v)
537 {
538   struct deflate_state *state = (struct deflate_state *)v;
539 
540   inflateEnd(&state->cx);
541   free(state);
542 }
543 
544 static void
545 DeflateTermOutput(void *v)
546 {
547   struct deflate_state *state = (struct deflate_state *)v;
548 
549   deflateEnd(&state->cx);
550   free(state);
551 }
552 
553 const struct ccp_algorithm PppdDeflateAlgorithm = {
554   TY_PPPD_DEFLATE,	/* pppd (wrongly) expects this ``type'' field */
555   CCP_NEG_DEFLATE24,
556   DeflateDispOpts,
557   {
558     DeflateSetOptsInput,
559     DeflateInitInput,
560     DeflateTermInput,
561     DeflateResetInput,
562     DeflateInput,
563     DeflateDictSetup
564   },
565   {
566     DeflateInitOptsOutput,
567     DeflateSetOptsOutput,
568     DeflateInitOutput,
569     DeflateTermOutput,
570     DeflateResetOutput,
571     DeflateOutput
572   },
573 };
574 
575 const struct ccp_algorithm DeflateAlgorithm = {
576   TY_DEFLATE,		/* rfc 1979 */
577   CCP_NEG_DEFLATE,
578   DeflateDispOpts,
579   {
580     DeflateSetOptsInput,
581     DeflateInitInput,
582     DeflateTermInput,
583     DeflateResetInput,
584     DeflateInput,
585     DeflateDictSetup
586   },
587   {
588     DeflateInitOptsOutput,
589     DeflateSetOptsOutput,
590     DeflateInitOutput,
591     DeflateTermOutput,
592     DeflateResetOutput,
593     DeflateOutput
594   },
595 };
596