bsd-comp.c 29 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120
  1. /* Because this code is derived from the 4.3BSD compress source:
  2. *
  3. *
  4. * Copyright (c) 1985, 1986 The Regents of the University of California.
  5. * All rights reserved.
  6. *
  7. * This code is derived from software contributed to Berkeley by
  8. * James A. Woods, derived from original work by Spencer Thomas
  9. * and Joseph Orost.
  10. *
  11. * Redistribution and use in source and binary forms, with or without
  12. * modification, are permitted provided that the following conditions
  13. * are met:
  14. * 1. Redistributions of source code must retain the above copyright
  15. * notice, this list of conditions and the following disclaimer.
  16. * 2. Redistributions in binary form must reproduce the above copyright
  17. * notice, this list of conditions and the following disclaimer in the
  18. * documentation and/or other materials provided with the distribution.
  19. * 3. All advertising materials mentioning features or use of this software
  20. * must display the following acknowledgement:
  21. * This product includes software developed by the University of
  22. * California, Berkeley and its contributors.
  23. * 4. Neither the name of the University nor the names of its contributors
  24. * may be used to endorse or promote products derived from this software
  25. * without specific prior written permission.
  26. *
  27. * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  28. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  29. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  30. * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  31. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  32. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  33. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  34. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  35. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  36. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  37. * SUCH DAMAGE.
  38. */
  39. /*
  40. * This version is for use with STREAMS under SunOS 4.x,
  41. * Digital UNIX, AIX 4.x, and SVR4 systems including Solaris 2.
  42. *
  43. * $Id: bsd-comp.c,v 1.21 2004/01/17 05:47:55 carlsonj Exp $
  44. */
  45. #ifdef AIX4
  46. #include <net/net_globals.h>
  47. #endif
  48. #include <sys/param.h>
  49. #include <sys/types.h>
  50. #include <sys/stream.h>
  51. #include <net/ppp_defs.h>
  52. #include "ppp_mod.h"
  53. #ifdef SVR4
  54. #include <sys/byteorder.h>
  55. #ifndef _BIG_ENDIAN
  56. #define BSD_LITTLE_ENDIAN
  57. #endif
  58. #endif
  59. #ifdef __osf__
  60. #undef FIRST
  61. #undef LAST
  62. #define BSD_LITTLE_ENDIAN
  63. #endif
  64. #ifdef SOL2
  65. #include <sys/sunddi.h>
  66. #endif
  67. #define PACKETPTR mblk_t *
  68. #include <net/ppp-comp.h>
  69. #if DO_BSD_COMPRESS
  70. /*
  71. * PPP "BSD compress" compression
  72. * The differences between this compression and the classic BSD LZW
  73. * source are obvious from the requirement that the classic code worked
  74. * with files while this handles arbitrarily long streams that
  75. * are broken into packets. They are:
  76. *
  77. * When the code size expands, a block of junk is not emitted by
  78. * the compressor and not expected by the decompressor.
  79. *
  80. * New codes are not necessarily assigned every time an old
  81. * code is output by the compressor. This is because a packet
  82. * end forces a code to be emitted, but does not imply that a
  83. * new sequence has been seen.
  84. *
  85. * The compression ratio is checked at the first end of a packet
  86. * after the appropriate gap. Besides simplifying and speeding
  87. * things up, this makes it more likely that the transmitter
  88. * and receiver will agree when the dictionary is cleared when
  89. * compression is not going well.
  90. */
  91. /*
  92. * A dictionary for doing BSD compress.
  93. */
  94. struct bsd_db {
  95. int totlen; /* length of this structure */
  96. u_int hsize; /* size of the hash table */
  97. u_char hshift; /* used in hash function */
  98. u_char n_bits; /* current bits/code */
  99. u_char maxbits;
  100. u_char debug;
  101. u_char unit;
  102. u_short seqno; /* sequence number of next packet */
  103. u_int hdrlen; /* header length to preallocate */
  104. u_int mru;
  105. u_int maxmaxcode; /* largest valid code */
  106. u_int max_ent; /* largest code in use */
  107. u_int in_count; /* uncompressed bytes, aged */
  108. u_int bytes_out; /* compressed bytes, aged */
  109. u_int ratio; /* recent compression ratio */
  110. u_int checkpoint; /* when to next check the ratio */
  111. u_int clear_count; /* times dictionary cleared */
  112. u_int incomp_count; /* incompressible packets */
  113. u_int incomp_bytes; /* incompressible bytes */
  114. u_int uncomp_count; /* uncompressed packets */
  115. u_int uncomp_bytes; /* uncompressed bytes */
  116. u_int comp_count; /* compressed packets */
  117. u_int comp_bytes; /* compressed bytes */
  118. u_short *lens; /* array of lengths of codes */
  119. struct bsd_dict {
  120. union { /* hash value */
  121. u_int32_t fcode;
  122. struct {
  123. #ifdef BSD_LITTLE_ENDIAN
  124. u_short prefix; /* preceding code */
  125. u_char suffix; /* last character of new code */
  126. u_char pad;
  127. #else
  128. u_char pad;
  129. u_char suffix; /* last character of new code */
  130. u_short prefix; /* preceding code */
  131. #endif
  132. } hs;
  133. } f;
  134. u_short codem1; /* output of hash table -1 */
  135. u_short cptr; /* map code to hash table entry */
  136. } dict[1];
  137. };
  138. #define BSD_OVHD 2 /* BSD compress overhead/packet */
  139. #define BSD_INIT_BITS BSD_MIN_BITS
  140. static void *bsd_comp_alloc __P((u_char *options, int opt_len));
  141. static void *bsd_decomp_alloc __P((u_char *options, int opt_len));
  142. static void bsd_free __P((void *state));
  143. static int bsd_comp_init __P((void *state, u_char *options, int opt_len,
  144. int unit, int hdrlen, int debug));
  145. static int bsd_decomp_init __P((void *state, u_char *options, int opt_len,
  146. int unit, int hdrlen, int mru, int debug));
  147. static int bsd_compress __P((void *state, mblk_t **mret,
  148. mblk_t *mp, int slen, int maxolen));
  149. static void bsd_incomp __P((void *state, mblk_t *dmsg));
  150. static int bsd_decompress __P((void *state, mblk_t *cmp, mblk_t **dmpp));
  151. static void bsd_reset __P((void *state));
  152. static void bsd_comp_stats __P((void *state, struct compstat *stats));
  153. /*
  154. * Procedures exported to ppp_comp.c.
  155. */
  156. struct compressor ppp_bsd_compress = {
  157. CI_BSD_COMPRESS, /* compress_proto */
  158. bsd_comp_alloc, /* comp_alloc */
  159. bsd_free, /* comp_free */
  160. bsd_comp_init, /* comp_init */
  161. bsd_reset, /* comp_reset */
  162. bsd_compress, /* compress */
  163. bsd_comp_stats, /* comp_stat */
  164. bsd_decomp_alloc, /* decomp_alloc */
  165. bsd_free, /* decomp_free */
  166. bsd_decomp_init, /* decomp_init */
  167. bsd_reset, /* decomp_reset */
  168. bsd_decompress, /* decompress */
  169. bsd_incomp, /* incomp */
  170. bsd_comp_stats, /* decomp_stat */
  171. };
  172. /*
  173. * the next two codes should not be changed lightly, as they must not
  174. * lie within the contiguous general code space.
  175. */
  176. #define CLEAR 256 /* table clear output code */
  177. #define FIRST 257 /* first free entry */
  178. #define LAST 255
  179. #define MAXCODE(b) ((1 << (b)) - 1)
  180. #define BADCODEM1 MAXCODE(BSD_MAX_BITS)
  181. #define BSD_HASH(prefix,suffix,hshift) ((((u_int32_t)(suffix)) << (hshift)) \
  182. ^ (u_int32_t)(prefix))
  183. #define BSD_KEY(prefix,suffix) ((((u_int32_t)(suffix)) << 16) \
  184. + (u_int32_t)(prefix))
  185. #define CHECK_GAP 10000 /* Ratio check interval */
  186. #define RATIO_SCALE_LOG 8
  187. #define RATIO_SCALE (1<<RATIO_SCALE_LOG)
  188. #define RATIO_MAX (0x7fffffff>>RATIO_SCALE_LOG)
  189. #define DECOMP_CHUNK 256
  190. /*
  191. * clear the dictionary
  192. */
  193. static void
  194. bsd_clear(db)
  195. struct bsd_db *db;
  196. {
  197. db->clear_count++;
  198. db->max_ent = FIRST-1;
  199. db->n_bits = BSD_INIT_BITS;
  200. db->ratio = 0;
  201. db->bytes_out = 0;
  202. db->in_count = 0;
  203. db->checkpoint = CHECK_GAP;
  204. }
  205. /*
  206. * If the dictionary is full, then see if it is time to reset it.
  207. *
  208. * Compute the compression ratio using fixed-point arithmetic
  209. * with 8 fractional bits.
  210. *
  211. * Since we have an infinite stream instead of a single file,
  212. * watch only the local compression ratio.
  213. *
  214. * Since both peers must reset the dictionary at the same time even in
  215. * the absence of CLEAR codes (while packets are incompressible), they
  216. * must compute the same ratio.
  217. */
  218. static int /* 1=output CLEAR */
  219. bsd_check(db)
  220. struct bsd_db *db;
  221. {
  222. u_int new_ratio;
  223. if (db->in_count >= db->checkpoint) {
  224. /* age the ratio by limiting the size of the counts */
  225. if (db->in_count >= RATIO_MAX
  226. || db->bytes_out >= RATIO_MAX) {
  227. db->in_count -= db->in_count/4;
  228. db->bytes_out -= db->bytes_out/4;
  229. }
  230. db->checkpoint = db->in_count + CHECK_GAP;
  231. if (db->max_ent >= db->maxmaxcode) {
  232. /* Reset the dictionary only if the ratio is worse,
  233. * or if it looks as if it has been poisoned
  234. * by incompressible data.
  235. *
  236. * This does not overflow, because
  237. * db->in_count <= RATIO_MAX.
  238. */
  239. new_ratio = db->in_count << RATIO_SCALE_LOG;
  240. if (db->bytes_out != 0)
  241. new_ratio /= db->bytes_out;
  242. if (new_ratio < db->ratio || new_ratio < 1 * RATIO_SCALE) {
  243. bsd_clear(db);
  244. return 1;
  245. }
  246. db->ratio = new_ratio;
  247. }
  248. }
  249. return 0;
  250. }
  251. /*
  252. * Return statistics.
  253. */
  254. static void
  255. bsd_comp_stats(state, stats)
  256. void *state;
  257. struct compstat *stats;
  258. {
  259. struct bsd_db *db = (struct bsd_db *) state;
  260. u_int out;
  261. stats->unc_bytes = db->uncomp_bytes;
  262. stats->unc_packets = db->uncomp_count;
  263. stats->comp_bytes = db->comp_bytes;
  264. stats->comp_packets = db->comp_count;
  265. stats->inc_bytes = db->incomp_bytes;
  266. stats->inc_packets = db->incomp_count;
  267. stats->ratio = db->in_count;
  268. out = db->bytes_out;
  269. if (stats->ratio <= 0x7fffff)
  270. stats->ratio <<= 8;
  271. else
  272. out >>= 8;
  273. if (out != 0)
  274. stats->ratio /= out;
  275. }
  276. /*
  277. * Reset state, as on a CCP ResetReq.
  278. */
  279. static void
  280. bsd_reset(state)
  281. void *state;
  282. {
  283. struct bsd_db *db = (struct bsd_db *) state;
  284. db->seqno = 0;
  285. bsd_clear(db);
  286. db->clear_count = 0;
  287. }
  288. /*
  289. * Allocate space for a (de) compressor.
  290. */
  291. static void *
  292. bsd_alloc(options, opt_len, decomp)
  293. u_char *options;
  294. int opt_len, decomp;
  295. {
  296. int bits;
  297. u_int newlen, hsize, hshift, maxmaxcode;
  298. struct bsd_db *db;
  299. if (opt_len != 3 || options[0] != CI_BSD_COMPRESS || options[1] != 3
  300. || BSD_VERSION(options[2]) != BSD_CURRENT_VERSION)
  301. return NULL;
  302. bits = BSD_NBITS(options[2]);
  303. switch (bits) {
  304. case 9: /* needs 82152 for both directions */
  305. case 10: /* needs 84144 */
  306. case 11: /* needs 88240 */
  307. case 12: /* needs 96432 */
  308. hsize = 5003;
  309. hshift = 4;
  310. break;
  311. case 13: /* needs 176784 */
  312. hsize = 9001;
  313. hshift = 5;
  314. break;
  315. case 14: /* needs 353744 */
  316. hsize = 18013;
  317. hshift = 6;
  318. break;
  319. case 15: /* needs 691440 */
  320. hsize = 35023;
  321. hshift = 7;
  322. break;
  323. case 16: /* needs 1366160--far too much, */
  324. /* hsize = 69001; */ /* and 69001 is too big for cptr */
  325. /* hshift = 8; */ /* in struct bsd_db */
  326. /* break; */
  327. default:
  328. return NULL;
  329. }
  330. maxmaxcode = MAXCODE(bits);
  331. newlen = sizeof(*db) + (hsize-1) * (sizeof(db->dict[0]));
  332. #ifdef __osf__
  333. db = (struct bsd_db *) ALLOC_SLEEP(newlen);
  334. #else
  335. db = (struct bsd_db *) ALLOC_NOSLEEP(newlen);
  336. #endif
  337. if (!db)
  338. return NULL;
  339. bzero(db, sizeof(*db) - sizeof(db->dict));
  340. if (!decomp) {
  341. db->lens = NULL;
  342. } else {
  343. #ifdef __osf__
  344. db->lens = (u_short *) ALLOC_SLEEP((maxmaxcode+1) * sizeof(db->lens[0]));
  345. #else
  346. db->lens = (u_short *) ALLOC_NOSLEEP((maxmaxcode+1) * sizeof(db->lens[0]));
  347. #endif
  348. if (!db->lens) {
  349. FREE(db, newlen);
  350. return NULL;
  351. }
  352. }
  353. db->totlen = newlen;
  354. db->hsize = hsize;
  355. db->hshift = hshift;
  356. db->maxmaxcode = maxmaxcode;
  357. db->maxbits = bits;
  358. return (void *) db;
  359. }
  360. static void
  361. bsd_free(state)
  362. void *state;
  363. {
  364. struct bsd_db *db = (struct bsd_db *) state;
  365. if (db->lens)
  366. FREE(db->lens, (db->maxmaxcode+1) * sizeof(db->lens[0]));
  367. FREE(db, db->totlen);
  368. }
  369. static void *
  370. bsd_comp_alloc(options, opt_len)
  371. u_char *options;
  372. int opt_len;
  373. {
  374. return bsd_alloc(options, opt_len, 0);
  375. }
  376. static void *
  377. bsd_decomp_alloc(options, opt_len)
  378. u_char *options;
  379. int opt_len;
  380. {
  381. return bsd_alloc(options, opt_len, 1);
  382. }
  383. /*
  384. * Initialize the database.
  385. */
  386. static int
  387. bsd_init(db, options, opt_len, unit, hdrlen, mru, debug, decomp)
  388. struct bsd_db *db;
  389. u_char *options;
  390. int opt_len, unit, hdrlen, mru, debug, decomp;
  391. {
  392. int i;
  393. if (opt_len < CILEN_BSD_COMPRESS
  394. || options[0] != CI_BSD_COMPRESS || options[1] != CILEN_BSD_COMPRESS
  395. || BSD_VERSION(options[2]) != BSD_CURRENT_VERSION
  396. || BSD_NBITS(options[2]) != db->maxbits
  397. || decomp && db->lens == NULL)
  398. return 0;
  399. if (decomp) {
  400. i = LAST+1;
  401. while (i != 0)
  402. db->lens[--i] = 1;
  403. }
  404. i = db->hsize;
  405. while (i != 0) {
  406. db->dict[--i].codem1 = BADCODEM1;
  407. db->dict[i].cptr = 0;
  408. }
  409. db->unit = unit;
  410. db->hdrlen = hdrlen;
  411. db->mru = mru;
  412. if (debug)
  413. db->debug = 1;
  414. bsd_reset(db);
  415. return 1;
  416. }
  417. static int
  418. bsd_comp_init(state, options, opt_len, unit, hdrlen, debug)
  419. void *state;
  420. u_char *options;
  421. int opt_len, unit, hdrlen, debug;
  422. {
  423. return bsd_init((struct bsd_db *) state, options, opt_len,
  424. unit, hdrlen, 0, debug, 0);
  425. }
  426. static int
  427. bsd_decomp_init(state, options, opt_len, unit, hdrlen, mru, debug)
  428. void *state;
  429. u_char *options;
  430. int opt_len, unit, hdrlen, mru, debug;
  431. {
  432. return bsd_init((struct bsd_db *) state, options, opt_len,
  433. unit, hdrlen, mru, debug, 1);
  434. }
  435. /*
  436. * compress a packet
  437. * One change from the BSD compress command is that when the
  438. * code size expands, we do not output a bunch of padding.
  439. *
  440. * N.B. at present, we ignore the hdrlen specified in the comp_init call.
  441. */
  442. static int /* new slen */
  443. bsd_compress(state, mretp, mp, slen, maxolen)
  444. void *state;
  445. mblk_t **mretp; /* return compressed mbuf chain here */
  446. mblk_t *mp; /* from here */
  447. int slen; /* uncompressed length */
  448. int maxolen; /* max compressed length */
  449. {
  450. struct bsd_db *db = (struct bsd_db *) state;
  451. int hshift = db->hshift;
  452. u_int max_ent = db->max_ent;
  453. u_int n_bits = db->n_bits;
  454. u_int bitno = 32;
  455. u_int32_t accm = 0, fcode;
  456. struct bsd_dict *dictp;
  457. u_char c;
  458. int hval, disp, ent, ilen;
  459. mblk_t *np, *mret;
  460. u_char *rptr, *wptr;
  461. u_char *cp_end;
  462. int olen;
  463. mblk_t *m, **mnp;
  464. #define PUTBYTE(v) { \
  465. if (wptr) { \
  466. *wptr++ = (v); \
  467. if (wptr >= cp_end) { \
  468. m->b_wptr = wptr; \
  469. m = m->b_cont; \
  470. if (m) { \
  471. wptr = m->b_wptr; \
  472. cp_end = m->b_datap->db_lim; \
  473. } else \
  474. wptr = NULL; \
  475. } \
  476. } \
  477. ++olen; \
  478. }
  479. #define OUTPUT(ent) { \
  480. bitno -= n_bits; \
  481. accm |= ((ent) << bitno); \
  482. do { \
  483. PUTBYTE(accm >> 24); \
  484. accm <<= 8; \
  485. bitno += 8; \
  486. } while (bitno <= 24); \
  487. }
  488. /*
  489. * First get the protocol and check that we're
  490. * interested in this packet.
  491. */
  492. *mretp = NULL;
  493. rptr = mp->b_rptr;
  494. if (rptr + PPP_HDRLEN > mp->b_wptr) {
  495. if (!pullupmsg(mp, PPP_HDRLEN))
  496. return 0;
  497. rptr = mp->b_rptr;
  498. }
  499. ent = PPP_PROTOCOL(rptr); /* get the protocol */
  500. if (ent < 0x21 || ent > 0xf9)
  501. return 0;
  502. /* Don't generate compressed packets which are larger than
  503. the uncompressed packet. */
  504. if (maxolen > slen)
  505. maxolen = slen;
  506. /* Allocate enough message blocks to give maxolen total space. */
  507. mnp = &mret;
  508. for (olen = maxolen; olen > 0; ) {
  509. m = allocb((olen < 4096? olen: 4096), BPRI_MED);
  510. *mnp = m;
  511. if (m == NULL) {
  512. if (mret != NULL) {
  513. freemsg(mret);
  514. mnp = &mret;
  515. }
  516. break;
  517. }
  518. mnp = &m->b_cont;
  519. olen -= m->b_datap->db_lim - m->b_wptr;
  520. }
  521. *mnp = NULL;
  522. if ((m = mret) != NULL) {
  523. wptr = m->b_wptr;
  524. cp_end = m->b_datap->db_lim;
  525. } else
  526. wptr = cp_end = NULL;
  527. olen = 0;
  528. /*
  529. * Copy the PPP header over, changing the protocol,
  530. * and install the 2-byte sequence number.
  531. */
  532. if (wptr) {
  533. wptr[0] = PPP_ADDRESS(rptr);
  534. wptr[1] = PPP_CONTROL(rptr);
  535. wptr[2] = 0; /* change the protocol */
  536. wptr[3] = PPP_COMP;
  537. wptr[4] = db->seqno >> 8;
  538. wptr[5] = db->seqno;
  539. wptr += PPP_HDRLEN + BSD_OVHD;
  540. }
  541. ++db->seqno;
  542. rptr += PPP_HDRLEN;
  543. slen = mp->b_wptr - rptr;
  544. ilen = slen + 1;
  545. np = mp->b_cont;
  546. for (;;) {
  547. if (slen <= 0) {
  548. if (!np)
  549. break;
  550. rptr = np->b_rptr;
  551. slen = np->b_wptr - rptr;
  552. np = np->b_cont;
  553. if (!slen)
  554. continue; /* handle 0-length buffers */
  555. ilen += slen;
  556. }
  557. slen--;
  558. c = *rptr++;
  559. fcode = BSD_KEY(ent, c);
  560. hval = BSD_HASH(ent, c, hshift);
  561. dictp = &db->dict[hval];
  562. /* Validate and then check the entry. */
  563. if (dictp->codem1 >= max_ent)
  564. goto nomatch;
  565. if (dictp->f.fcode == fcode) {
  566. ent = dictp->codem1+1;
  567. continue; /* found (prefix,suffix) */
  568. }
  569. /* continue probing until a match or invalid entry */
  570. disp = (hval == 0) ? 1 : hval;
  571. do {
  572. hval += disp;
  573. if (hval >= db->hsize)
  574. hval -= db->hsize;
  575. dictp = &db->dict[hval];
  576. if (dictp->codem1 >= max_ent)
  577. goto nomatch;
  578. } while (dictp->f.fcode != fcode);
  579. ent = dictp->codem1 + 1; /* finally found (prefix,suffix) */
  580. continue;
  581. nomatch:
  582. OUTPUT(ent); /* output the prefix */
  583. /* code -> hashtable */
  584. if (max_ent < db->maxmaxcode) {
  585. struct bsd_dict *dictp2;
  586. /* expand code size if needed */
  587. if (max_ent >= MAXCODE(n_bits))
  588. db->n_bits = ++n_bits;
  589. /* Invalidate old hash table entry using
  590. * this code, and then take it over.
  591. */
  592. dictp2 = &db->dict[max_ent+1];
  593. if (db->dict[dictp2->cptr].codem1 == max_ent)
  594. db->dict[dictp2->cptr].codem1 = BADCODEM1;
  595. dictp2->cptr = hval;
  596. dictp->codem1 = max_ent;
  597. dictp->f.fcode = fcode;
  598. db->max_ent = ++max_ent;
  599. }
  600. ent = c;
  601. }
  602. OUTPUT(ent); /* output the last code */
  603. db->bytes_out += olen;
  604. db->in_count += ilen;
  605. if (bitno < 32)
  606. ++db->bytes_out; /* count complete bytes */
  607. if (bsd_check(db))
  608. OUTPUT(CLEAR); /* do not count the CLEAR */
  609. /*
  610. * Pad dribble bits of last code with ones.
  611. * Do not emit a completely useless byte of ones.
  612. */
  613. if (bitno != 32)
  614. PUTBYTE((accm | (0xff << (bitno-8))) >> 24);
  615. /*
  616. * Increase code size if we would have without the packet
  617. * boundary and as the decompressor will.
  618. */
  619. if (max_ent >= MAXCODE(n_bits) && max_ent < db->maxmaxcode)
  620. db->n_bits++;
  621. db->uncomp_bytes += ilen;
  622. ++db->uncomp_count;
  623. if (olen + PPP_HDRLEN + BSD_OVHD > maxolen && mret != NULL) {
  624. /* throw away the compressed stuff if it is longer than uncompressed */
  625. freemsg(mret);
  626. mret = NULL;
  627. ++db->incomp_count;
  628. db->incomp_bytes += ilen;
  629. } else if (wptr != NULL) {
  630. m->b_wptr = wptr;
  631. if (m->b_cont) {
  632. freemsg(m->b_cont);
  633. m->b_cont = NULL;
  634. }
  635. ++db->comp_count;
  636. db->comp_bytes += olen + BSD_OVHD;
  637. }
  638. *mretp = mret;
  639. return olen + PPP_HDRLEN + BSD_OVHD;
  640. #undef OUTPUT
  641. #undef PUTBYTE
  642. }
  643. /*
  644. * Update the "BSD Compress" dictionary on the receiver for
  645. * incompressible data by pretending to compress the incoming data.
  646. */
  647. static void
  648. bsd_incomp(state, dmsg)
  649. void *state;
  650. mblk_t *dmsg;
  651. {
  652. struct bsd_db *db = (struct bsd_db *) state;
  653. u_int hshift = db->hshift;
  654. u_int max_ent = db->max_ent;
  655. u_int n_bits = db->n_bits;
  656. struct bsd_dict *dictp;
  657. u_int32_t fcode;
  658. u_char c;
  659. long hval, disp;
  660. int slen, ilen;
  661. u_int bitno = 7;
  662. u_char *rptr;
  663. u_int ent;
  664. rptr = dmsg->b_rptr;
  665. if (rptr + PPP_HDRLEN > dmsg->b_wptr) {
  666. if (!pullupmsg(dmsg, PPP_HDRLEN))
  667. return;
  668. rptr = dmsg->b_rptr;
  669. }
  670. ent = PPP_PROTOCOL(rptr); /* get the protocol */
  671. if (ent < 0x21 || ent > 0xf9)
  672. return;
  673. db->seqno++;
  674. ilen = 1; /* count the protocol as 1 byte */
  675. rptr += PPP_HDRLEN;
  676. for (;;) {
  677. slen = dmsg->b_wptr - rptr;
  678. if (slen <= 0) {
  679. dmsg = dmsg->b_cont;
  680. if (!dmsg)
  681. break;
  682. rptr = dmsg->b_rptr;
  683. continue; /* skip zero-length buffers */
  684. }
  685. ilen += slen;
  686. do {
  687. c = *rptr++;
  688. fcode = BSD_KEY(ent, c);
  689. hval = BSD_HASH(ent, c, hshift);
  690. dictp = &db->dict[hval];
  691. /* validate and then check the entry */
  692. if (dictp->codem1 >= max_ent)
  693. goto nomatch;
  694. if (dictp->f.fcode == fcode) {
  695. ent = dictp->codem1+1;
  696. continue; /* found (prefix,suffix) */
  697. }
  698. /* continue probing until a match or invalid entry */
  699. disp = (hval == 0) ? 1 : hval;
  700. do {
  701. hval += disp;
  702. if (hval >= db->hsize)
  703. hval -= db->hsize;
  704. dictp = &db->dict[hval];
  705. if (dictp->codem1 >= max_ent)
  706. goto nomatch;
  707. } while (dictp->f.fcode != fcode);
  708. ent = dictp->codem1+1;
  709. continue; /* finally found (prefix,suffix) */
  710. nomatch: /* output (count) the prefix */
  711. bitno += n_bits;
  712. /* code -> hashtable */
  713. if (max_ent < db->maxmaxcode) {
  714. struct bsd_dict *dictp2;
  715. /* expand code size if needed */
  716. if (max_ent >= MAXCODE(n_bits))
  717. db->n_bits = ++n_bits;
  718. /* Invalidate previous hash table entry
  719. * assigned this code, and then take it over.
  720. */
  721. dictp2 = &db->dict[max_ent+1];
  722. if (db->dict[dictp2->cptr].codem1 == max_ent)
  723. db->dict[dictp2->cptr].codem1 = BADCODEM1;
  724. dictp2->cptr = hval;
  725. dictp->codem1 = max_ent;
  726. dictp->f.fcode = fcode;
  727. db->max_ent = ++max_ent;
  728. db->lens[max_ent] = db->lens[ent]+1;
  729. }
  730. ent = c;
  731. } while (--slen != 0);
  732. }
  733. bitno += n_bits; /* output (count) the last code */
  734. db->bytes_out += bitno/8;
  735. db->in_count += ilen;
  736. (void)bsd_check(db);
  737. ++db->incomp_count;
  738. db->incomp_bytes += ilen;
  739. ++db->uncomp_count;
  740. db->uncomp_bytes += ilen;
  741. /* Increase code size if we would have without the packet
  742. * boundary and as the decompressor will.
  743. */
  744. if (max_ent >= MAXCODE(n_bits) && max_ent < db->maxmaxcode)
  745. db->n_bits++;
  746. }
  747. /*
  748. * Decompress "BSD Compress"
  749. *
  750. * Because of patent problems, we return DECOMP_ERROR for errors
  751. * found by inspecting the input data and for system problems, but
  752. * DECOMP_FATALERROR for any errors which could possibly be said to
  753. * be being detected "after" decompression. For DECOMP_ERROR,
  754. * we can issue a CCP reset-request; for DECOMP_FATALERROR, we may be
  755. * infringing a patent of Motorola's if we do, so we take CCP down
  756. * instead.
  757. *
  758. * Given that the frame has the correct sequence number and a good FCS,
  759. * errors such as invalid codes in the input most likely indicate a
  760. * bug, so we return DECOMP_FATALERROR for them in order to turn off
  761. * compression, even though they are detected by inspecting the input.
  762. */
  763. static int
  764. bsd_decompress(state, cmsg, dmpp)
  765. void *state;
  766. mblk_t *cmsg, **dmpp;
  767. {
  768. struct bsd_db *db = (struct bsd_db *) state;
  769. u_int max_ent = db->max_ent;
  770. u_int32_t accm = 0;
  771. u_int bitno = 32; /* 1st valid bit in accm */
  772. u_int n_bits = db->n_bits;
  773. u_int tgtbitno = 32-n_bits; /* bitno when we have a code */
  774. struct bsd_dict *dictp;
  775. int explen, i, seq, len;
  776. u_int incode, oldcode, finchar;
  777. u_char *p, *rptr, *wptr;
  778. mblk_t *dmsg, *mret;
  779. int adrs, ctrl, ilen;
  780. int dlen, space, codelen, extra;
  781. /*
  782. * Get at least the BSD Compress header in the first buffer
  783. */
  784. rptr = cmsg->b_rptr;
  785. if (rptr + PPP_HDRLEN + BSD_OVHD >= cmsg->b_wptr) {
  786. if (!pullupmsg(cmsg, PPP_HDRLEN + BSD_OVHD + 1)) {
  787. if (db->debug)
  788. printf("bsd_decomp%d: failed to pullup\n", db->unit);
  789. return DECOMP_ERROR;
  790. }
  791. rptr = cmsg->b_rptr;
  792. }
  793. /*
  794. * Save the address/control from the PPP header
  795. * and then get the sequence number.
  796. */
  797. adrs = PPP_ADDRESS(rptr);
  798. ctrl = PPP_CONTROL(rptr);
  799. rptr += PPP_HDRLEN;
  800. seq = (rptr[0] << 8) + rptr[1];
  801. rptr += BSD_OVHD;
  802. ilen = len = cmsg->b_wptr - rptr;
  803. /*
  804. * Check the sequence number and give up if it is not what we expect.
  805. */
  806. if (seq != db->seqno++) {
  807. if (db->debug)
  808. printf("bsd_decomp%d: bad sequence # %d, expected %d\n",
  809. db->unit, seq, db->seqno - 1);
  810. return DECOMP_ERROR;
  811. }
  812. /*
  813. * Allocate one message block to start with.
  814. */
  815. if ((dmsg = allocb(DECOMP_CHUNK + db->hdrlen, BPRI_MED)) == NULL)
  816. return DECOMP_ERROR;
  817. mret = dmsg;
  818. dmsg->b_wptr += db->hdrlen;
  819. dmsg->b_rptr = wptr = dmsg->b_wptr;
  820. /* Fill in the ppp header, but not the last byte of the protocol
  821. (that comes from the decompressed data). */
  822. wptr[0] = adrs;
  823. wptr[1] = ctrl;
  824. wptr[2] = 0;
  825. wptr += PPP_HDRLEN - 1;
  826. space = dmsg->b_datap->db_lim - wptr;
  827. oldcode = CLEAR;
  828. explen = 0;
  829. for (;;) {
  830. if (len == 0) {
  831. cmsg = cmsg->b_cont;
  832. if (!cmsg) /* quit at end of message */
  833. break;
  834. rptr = cmsg->b_rptr;
  835. len = cmsg->b_wptr - rptr;
  836. ilen += len;
  837. continue; /* handle 0-length buffers */
  838. }
  839. /*
  840. * Accumulate bytes until we have a complete code.
  841. * Then get the next code, relying on the 32-bit,
  842. * unsigned accm to mask the result.
  843. */
  844. bitno -= 8;
  845. accm |= *rptr++ << bitno;
  846. --len;
  847. if (tgtbitno < bitno)
  848. continue;
  849. incode = accm >> tgtbitno;
  850. accm <<= n_bits;
  851. bitno += n_bits;
  852. if (incode == CLEAR) {
  853. /*
  854. * The dictionary must only be cleared at
  855. * the end of a packet. But there could be an
  856. * empty message block at the end.
  857. */
  858. if (len > 0 || cmsg->b_cont != 0) {
  859. if (cmsg->b_cont)
  860. len += msgdsize(cmsg->b_cont);
  861. if (len > 0) {
  862. freemsg(dmsg);
  863. if (db->debug)
  864. printf("bsd_decomp%d: bad CLEAR\n", db->unit);
  865. return DECOMP_FATALERROR;
  866. }
  867. }
  868. bsd_clear(db);
  869. explen = ilen = 0;
  870. break;
  871. }
  872. if (incode > max_ent + 2 || incode > db->maxmaxcode
  873. || incode > max_ent && oldcode == CLEAR) {
  874. freemsg(dmsg);
  875. if (db->debug) {
  876. printf("bsd_decomp%d: bad code 0x%x oldcode=0x%x ",
  877. db->unit, incode, oldcode);
  878. printf("max_ent=0x%x dlen=%d seqno=%d\n",
  879. max_ent, dlen, db->seqno);
  880. }
  881. return DECOMP_FATALERROR; /* probably a bug */
  882. }
  883. /* Special case for KwKwK string. */
  884. if (incode > max_ent) {
  885. finchar = oldcode;
  886. extra = 1;
  887. } else {
  888. finchar = incode;
  889. extra = 0;
  890. }
  891. codelen = db->lens[finchar];
  892. explen += codelen + extra;
  893. if (explen > db->mru + 1) {
  894. freemsg(dmsg);
  895. if (db->debug)
  896. printf("bsd_decomp%d: ran out of mru\n", db->unit);
  897. return DECOMP_FATALERROR;
  898. }
  899. /*
  900. * Decode this code and install it in the decompressed buffer.
  901. */
  902. space -= codelen + extra;
  903. if (space < 0) {
  904. /* Allocate another message block. */
  905. dmsg->b_wptr = wptr;
  906. dlen = codelen + extra;
  907. if (dlen < DECOMP_CHUNK)
  908. dlen = DECOMP_CHUNK;
  909. if ((dmsg->b_cont = allocb(dlen, BPRI_MED)) == NULL) {
  910. freemsg(dmsg);
  911. return DECOMP_ERROR;
  912. }
  913. dmsg = dmsg->b_cont;
  914. wptr = dmsg->b_wptr;
  915. space = dmsg->b_datap->db_lim - wptr - codelen - extra;
  916. }
  917. p = (wptr += codelen);
  918. while (finchar > LAST) {
  919. dictp = &db->dict[db->dict[finchar].cptr];
  920. #ifdef DEBUG
  921. --codelen;
  922. if (codelen <= 0) {
  923. freemsg(dmsg);
  924. printf("bsd_decomp%d: fell off end of chain ", db->unit);
  925. printf("0x%x at 0x%x by 0x%x, max_ent=0x%x\n",
  926. incode, finchar, db->dict[finchar].cptr, max_ent);
  927. return DECOMP_FATALERROR;
  928. }
  929. if (dictp->codem1 != finchar-1) {
  930. freemsg(dmsg);
  931. printf("bsd_decomp%d: bad code chain 0x%x finchar=0x%x ",
  932. db->unit, incode, finchar);
  933. printf("oldcode=0x%x cptr=0x%x codem1=0x%x\n", oldcode,
  934. db->dict[finchar].cptr, dictp->codem1);
  935. return DECOMP_FATALERROR;
  936. }
  937. #endif
  938. *--p = dictp->f.hs.suffix;
  939. finchar = dictp->f.hs.prefix;
  940. }
  941. *--p = finchar;
  942. #ifdef DEBUG
  943. if (--codelen != 0)
  944. printf("bsd_decomp%d: short by %d after code 0x%x, max_ent=0x%x\n",
  945. db->unit, codelen, incode, max_ent);
  946. #endif
  947. if (extra) /* the KwKwK case again */
  948. *wptr++ = finchar;
  949. /*
  950. * If not first code in a packet, and
  951. * if not out of code space, then allocate a new code.
  952. *
  953. * Keep the hash table correct so it can be used
  954. * with uncompressed packets.
  955. */
  956. if (oldcode != CLEAR && max_ent < db->maxmaxcode) {
  957. struct bsd_dict *dictp2;
  958. u_int32_t fcode;
  959. int hval, disp;
  960. fcode = BSD_KEY(oldcode,finchar);
  961. hval = BSD_HASH(oldcode,finchar,db->hshift);
  962. dictp = &db->dict[hval];
  963. /* look for a free hash table entry */
  964. if (dictp->codem1 < max_ent) {
  965. disp = (hval == 0) ? 1 : hval;
  966. do {
  967. hval += disp;
  968. if (hval >= db->hsize)
  969. hval -= db->hsize;
  970. dictp = &db->dict[hval];
  971. } while (dictp->codem1 < max_ent);
  972. }
  973. /*
  974. * Invalidate previous hash table entry
  975. * assigned this code, and then take it over
  976. */
  977. dictp2 = &db->dict[max_ent+1];
  978. if (db->dict[dictp2->cptr].codem1 == max_ent) {
  979. db->dict[dictp2->cptr].codem1 = BADCODEM1;
  980. }
  981. dictp2->cptr = hval;
  982. dictp->codem1 = max_ent;
  983. dictp->f.fcode = fcode;
  984. db->max_ent = ++max_ent;
  985. db->lens[max_ent] = db->lens[oldcode]+1;
  986. /* Expand code size if needed. */
  987. if (max_ent >= MAXCODE(n_bits) && max_ent < db->maxmaxcode) {
  988. db->n_bits = ++n_bits;
  989. tgtbitno = 32-n_bits;
  990. }
  991. }
  992. oldcode = incode;
  993. }
  994. dmsg->b_wptr = wptr;
  995. /*
  996. * Keep the checkpoint right so that incompressible packets
  997. * clear the dictionary at the right times.
  998. */
  999. db->bytes_out += ilen;
  1000. db->in_count += explen;
  1001. if (bsd_check(db) && db->debug) {
  1002. printf("bsd_decomp%d: peer should have cleared dictionary\n",
  1003. db->unit);
  1004. }
  1005. ++db->comp_count;
  1006. db->comp_bytes += ilen + BSD_OVHD;
  1007. ++db->uncomp_count;
  1008. db->uncomp_bytes += explen;
  1009. *dmpp = mret;
  1010. return DECOMP_OK;
  1011. }
  1012. #endif /* DO_BSD_COMPRESS */