📄 bsd-comp.c
字号:
} ++db->seqno; olen = 0; slen = mp->m_len; ilen = slen + 1; for (;;) { if (slen <= 0) break; slen--; c = *rptr++; fcode = BSD_KEY(ent, c); hval = BSD_HASH(ent, c, hshift); dictp = &db->dict[hval]; /* Validate and then check the entry. */ if (dictp->codem1 >= max_ent) goto nomatch; if (dictp->f.fcode == fcode) { ent = dictp->codem1+1; continue; /* found (prefix,suffix) */ } /* continue probing until a match or invalid entry */ disp = (hval == 0) ? 1 : hval; do { hval += disp; if (hval >= db->hsize) hval -= db->hsize; dictp = &db->dict[hval]; if (dictp->codem1 >= max_ent) goto nomatch; } while (dictp->f.fcode != fcode); ent = dictp->codem1 + 1; /* finally found (prefix,suffix) */ continue; nomatch: OUTPUT(ent); /* output the prefix */ /* code -> hashtable */ if (max_ent < db->maxmaxcode) { struct bsd_dict *dictp2; /* expand code size if needed */ if (max_ent >= MAXCODE(n_bits)) db->n_bits = ++n_bits; /* Invalidate old hash table entry using * this code, and then take it over. */ dictp2 = &db->dict[max_ent+1]; if (db->dict[dictp2->cptr].codem1 == max_ent) db->dict[dictp2->cptr].codem1 = BADCODEM1; dictp2->cptr = hval; dictp->codem1 = max_ent; dictp->f.fcode = fcode; db->max_ent = ++max_ent; } ent = c; } OUTPUT(ent); /* output the last code */ db->bytes_out += olen; db->in_count += ilen; if (bitno < 32) ++db->bytes_out; /* count complete bytes */ if (bsd_check(db)) OUTPUT(CLEAR); /* do not count the CLEAR */ /* * Pad dribble bits of last code with ones. * Do not emit a completely useless byte of ones. */ if (bitno != 32) PUTBYTE((accm | (0xff << (bitno-8))) >> 24); if (m != NULL) m->m_len = wptr - mtod(m, u_char *); /* * Increase code size if we would have without the packet * boundary and as the decompressor will. */ if (max_ent >= MAXCODE(n_bits) && max_ent < db->maxmaxcode) db->n_bits++; db->uncomp_bytes += ilen; ++db->uncomp_count; if (olen + PPP_HDRLEN + BSD_OVHD > maxolen) { /* throw away the compressed stuff if it is longer than uncompressed */ if (*mret != NULL) { m_freem(*mret); *mret = NULL; } ++db->incomp_count; db->incomp_bytes += ilen; } else { ++db->comp_count; db->comp_bytes += olen + BSD_OVHD; } return olen + BSD_OVHD; /* For stats */#undef OUTPUT#undef PUTBYTE}/* * Update the "BSD Compress" dictionary on the receiver for * incompressible data by pretending to compress the incoming data. */static voidbsd_incomp(state, dmsg, proto) void *state; struct mbuf *dmsg; int proto;{ struct bsd_db *db = (struct bsd_db *) state; u_int hshift = db->hshift; u_int max_ent = db->max_ent; u_int n_bits = db->n_bits; struct bsd_dict *dictp; u_int32_t fcode; u_char c; u_int32_t hval, disp; int slen, ilen; u_int bitno = 7; u_char *rptr; u_int ent; /* * If the protocol is not in the range we're interested in, * just return without looking at the packet. If it is, * the protocol becomes the first byte to "compress". */ rptr = mtod(dmsg, u_char *); ent = proto; if (ent < 0x21 || ent > 0xf9) return; db->incomp_count++; db->seqno++; ilen = 1; /* count the protocol as 1 byte */ slen = dmsg->m_len; for (;;) { if (slen <= 0) break; ilen += slen; do { c = *rptr++; fcode = BSD_KEY(ent, c); hval = BSD_HASH(ent, c, hshift); dictp = &db->dict[hval]; /* validate and then check the entry */ if (dictp->codem1 >= max_ent) goto nomatch; if (dictp->f.fcode == fcode) { ent = dictp->codem1+1; continue; /* found (prefix,suffix) */ } /* continue probing until a match or invalid entry */ disp = (hval == 0) ? 1 : hval; do { hval += disp; if (hval >= db->hsize) hval -= db->hsize; dictp = &db->dict[hval]; if (dictp->codem1 >= max_ent) goto nomatch; } while (dictp->f.fcode != fcode); ent = dictp->codem1+1; continue; /* finally found (prefix,suffix) */ nomatch: /* output (count) the prefix */ bitno += n_bits; /* code -> hashtable */ if (max_ent < db->maxmaxcode) { struct bsd_dict *dictp2; /* expand code size if needed */ if (max_ent >= MAXCODE(n_bits)) db->n_bits = ++n_bits; /* Invalidate previous hash table entry * assigned this code, and then take it over. */ dictp2 = &db->dict[max_ent+1]; if (db->dict[dictp2->cptr].codem1 == max_ent) db->dict[dictp2->cptr].codem1 = BADCODEM1; dictp2->cptr = hval; dictp->codem1 = max_ent; dictp->f.fcode = fcode; db->max_ent = ++max_ent; db->lens[max_ent] = db->lens[ent]+1; } ent = c; } while (--slen != 0); } bitno += n_bits; /* output (count) the last code */ db->bytes_out += bitno/8; db->in_count += ilen; (void)bsd_check(db); ++db->incomp_count; db->incomp_bytes += ilen; ++db->uncomp_count; db->uncomp_bytes += ilen; /* Increase code size if we would have without the packet * boundary and as the decompressor will. */ if (max_ent >= MAXCODE(n_bits) && max_ent < db->maxmaxcode) db->n_bits++;}/* * Decompress "BSD Compress". * * Because of patent problems, we return DECOMP_ERROR for errors * found by inspecting the input data and for system problems, but * DECOMP_FATALERROR for any errors which could possibly be said to * be being detected "after" decompression. For DECOMP_ERROR, * we can issue a CCP reset-request; for DECOMP_FATALERROR, we may be * infringing a patent of Motorola's if we do, so we take CCP down * instead. * * Given that the frame has the correct sequence number and a good FCS, * errors such as invalid codes in the input most likely indicate a * bug, so we return DECOMP_FATALERROR for them in order to turn off * compression, even though they are detected by inspecting the input. */intbsd_decompress(state, cmp, dmpp) void *state; struct mbuf *cmp, **dmpp;{ struct bsd_db *db = (struct bsd_db *) state; u_int max_ent = db->max_ent; u_int32_t accm = 0; u_int bitno = 32; /* 1st valid bit in accm */ u_int n_bits = db->n_bits; u_int tgtbitno = 32-n_bits; /* bitno when we have a code */ struct bsd_dict *dictp; int explen, i, seq, len; u_int incode, oldcode, finchar; u_char *p, *rptr, *wptr; struct mbuf *m, *dmp, *mret; int adrs, ctrl, ilen; int space, codelen, extra; struct mbuf *last; *dmpp = NULL; rptr = mtod(cmp, u_char *); len = cmp->m_len; seq = 0; for (i = 0; i < 2; ++i) { if (len <= 0) return DECOMP_ERROR; seq = (seq << 8) + *rptr++; --len; } /* * Check the sequence number and give up if it differs from * the value we're expecting. */ if (seq != db->seqno) { if (db->debug) printf("bsd_decomp%d: bad sequence # %d, expected %d\n", db->unit, seq, db->seqno - 1); return DECOMP_ERROR; } ++db->seqno; /* * Allocate one mbuf to start with. */ dmp = m_get(); if (dmp == NULL) return DECOMP_ERROR; dmp->m_data += if_maxlinkhdr; mret = dmp; dmp->m_data += db->hdrlen; wptr = mtod(dmp, u_char *); space = M_TRAILINGSPACE(dmp); /* * Fill in the ppp header, but not the last byte of the protocol * (that comes from the decompressed data). */ ilen = len; oldcode = CLEAR; explen = 0; for (;;) { if (len == 0) break; /* * Accumulate bytes until we have a complete code. * Then get the next code, relying on the 32-bit, * unsigned accm to mask the result. */ bitno -= 8; accm |= *rptr++ << bitno; --len; if (tgtbitno < bitno) continue; incode = accm >> tgtbitno; accm <<= n_bits; bitno += n_bits; if (incode == CLEAR) { /* * The dictionary must only be cleared at * the end of a packet. But there could be an * empty mbuf at the end. */ if (len > 0) { m_freem(mret); if (db->debug) printf("bsd_decomp%d: bad CLEAR\n", db->unit); return DECOMP_FATALERROR; /* probably a bug */ } bsd_clear(db); explen = ilen = 0; break; } if (incode > max_ent + 2 || incode > db->maxmaxcode || incode > max_ent && oldcode == CLEAR) { m_freem(mret); if (db->debug) { printf("bsd_decomp%d: bad code 0x%x oldcode=0x%x ", db->unit, incode, oldcode); printf("max_ent=0x%x explen=%d seqno=%d\n", max_ent, explen, db->seqno); } return DECOMP_FATALERROR; /* probably a bug */ } /* Special case for KwKwK string. */ if (incode > max_ent) { finchar = oldcode; extra = 1; } else { finchar = incode; extra = 0; } codelen = db->lens[finchar]; explen += codelen + extra; if (explen > db->mru + 1) { m_freem(mret); if (db->debug) { printf("bsd_decomp%d: ran out of mru\n", db->unit); } return DECOMP_FATALERROR; } /* * For simplicity, the decoded characters go in a single mbuf, * so we allocate a single extra cluster mbuf if necessary. */ if ((space -= codelen + extra) < 0) { m_inc(dmp, M_INC_COMP); space = M_TRAILINGSPACE(dmp) - (codelen + extra); if (space < 0) { /* now that's what I call *compression*. */ m_freem(mret); /* mret = dmp */ return DECOMP_ERROR; } wptr = mtod(dmp, u_char *); } /* * Decode this code and install it in the decompressed buffer. */ p = (wptr += codelen); while (finchar > LAST) { dictp = &db->dict[db->dict[finchar].cptr];#ifdef DEBUG if (--codelen <= 0 || dictp->codem1 != finchar-1) goto bad;#endif *--p = dictp->f.hs.suffix; finchar = dictp->f.hs.prefix; } *--p = finchar;#ifdef DEBUG if (--codelen != 0) printf("bsd_decomp%d: short by %d after code 0x%x, max_ent=0x%x\n", db->unit, codelen, incode, max_ent);#endif if (extra) /* the KwKwK case again */ *wptr++ = finchar; /* * If not first code in a packet, and * if not out of code space, then allocate a new code. * * Keep the hash table correct so it can be used * with uncompressed packets. */ if (oldcode != CLEAR && max_ent < db->maxmaxcode) { struct bsd_dict *dictp2; u_int32_t fcode; u_int32_t hval, disp; fcode = BSD_KEY(oldcode,finchar); hval = BSD_HASH(oldcode,finchar,db->hshift); dictp = &db->dict[hval]; /* look for a free hash table entry */ if (dictp->codem1 < max_ent) { disp = (hval == 0) ? 1 : hval; do { hval += disp; if (hval >= db->hsize) hval -= db->hsize; dictp = &db->dict[hval]; } while (dictp->codem1 < max_ent); } /* * Invalidate previous hash table entry * assigned this code, and then take it over */ dictp2 = &db->dict[max_ent+1]; if (db->dict[dictp2->cptr].codem1 == max_ent) { db->dict[dictp2->cptr].codem1 = BADCODEM1; } dictp2->cptr = hval; dictp->codem1 = max_ent; dictp->f.fcode = fcode; db->max_ent = ++max_ent; db->lens[max_ent] = db->lens[oldcode]+1; /* Expand code size if needed. */ if (max_ent >= MAXCODE(n_bits) && max_ent < db->maxmaxcode) { db->n_bits = ++n_bits; tgtbitno = 32-n_bits; } } oldcode = incode; } dmp->m_len = wptr - mtod(dmp, u_char *); /* * Keep the checkpoint right so that incompressible packets * clear the dictionary at the right times. */ db->bytes_out += ilen; db->in_count += explen; if (bsd_check(db) && db->debug) { printf("bsd_decomp%d: peer should have cleared dictionary\n", db->unit); } ++db->comp_count; db->comp_bytes += ilen + BSD_OVHD; ++db->uncomp_count; db->uncomp_bytes += explen; *dmpp = mret; return DECOMP_OK;#ifdef DEBUG bad: if (codelen <= 0) { printf("bsd_decomp%d: fell off end of chain ", db->unit); printf("0x%x at 0x%x by 0x%x, max_ent=0x%x\n", incode, finchar, db->dict[finchar].cptr, max_ent); } else if (dictp->codem1 != finchar-1) { printf("bsd_decomp%d: bad code chain 0x%x finchar=0x%x ", db->unit, incode, finchar); printf("oldcode=0x%x cptr=0x%x codem1=0x%x\n", oldcode, db->dict[finchar].cptr, dictp->codem1); } m_freem(mret); return DECOMP_FATALERROR;#endif /* DEBUG */}#endif /* DO_BSD_COMPRESS */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -